]> andersk Git - moira.git/blob - server/qrtn.qc
punt version 1 queries
[moira.git] / server / qrtn.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  * 
10  */
11
12 #ifndef lint
13 static char *rcsid_qrtn_qc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "sms_server.h"
19
20 char *Argv[16];
21
22 int ingres_errno = 0;
23 int sms_errcode = 0;
24 ## int query_timeout = 30;
25 extern char *whoami;
26 extern FILE *journal;
27
28 #define INGRES_BAD_INT 4111
29 #define INGRES_BAD_DATE 4302
30 #define INGRES_DEADLOCK 4700
31 #define INGRES_TIMEOUT 4702
32
33 /*
34  * ingerr: (supposedly) called when Ingres indicates an error.
35  * I have not yet been able to get this to work to intercept a
36  * database open error.
37  */
38
39 static int ingerr(num)
40     int *num;
41 {
42     ingres_errno = *num;
43
44     switch (*num) {
45     case INGRES_BAD_INT:
46         sms_errcode = SMS_INTEGER;
47         break;
48     case INGRES_BAD_DATE:
49         sms_errcode = SMS_DATE;
50         break;
51     case INGRES_DEADLOCK:
52         sms_errcode = SMS_DEADLOCK;
53         com_err(whoami, 0, "INGRES deadlock detected");
54         break;
55     case INGRES_TIMEOUT:
56         sms_errcode = SMS_BUSY;
57         com_err(whoami, 0, "timed out getting lock");
58         break;
59     default:
60         sms_errcode = SMS_INGRES_ERR;
61         com_err(whoami, SMS_INGRES_ERR, " code %d\n", *num);
62         critical_alert("SMS", "SMS server encountered INGRES ERROR %d", *num);
63         return (*num);
64     }
65     return (0);
66 }
67
68 int sms_open_database()
69 {
70     register int i;
71     char *malloc();
72
73     /* initialize local argv */
74     for (i = 0; i < 16; i++)
75         Argv[i] = malloc(ARGLEN);
76
77     IIseterr(ingerr);
78         
79     ingres_errno = 0;
80         
81     /* open the database */
82 ##  ingres sms
83 ##  set lockmode session where level = table, timeout = query_timeout
84 ##  set lockmode on capacls where readlock = shared
85 ##  set lockmode on alias where readlock = shared
86     return ingres_errno;
87 }
88
89 int sms_close_database()
90 {
91 ##  exit
92 }
93
94 sms_check_access(cl, name, argc, argv_ro)
95     client *cl;
96     char *name;
97     int argc;
98     char *argv_ro[];
99 {
100     struct query *q;
101     struct query *get_query_by_name();
102
103     ingres_errno = 0;
104
105     q = get_query_by_name(name, cl->args->sms_version_no);
106     if (q == (struct query *)0)
107         return(SMS_NO_HANDLE);
108
109     return(sms_verify_query(cl, q, argc, argv_ro));
110 }
111
112 sms_process_query(cl, name, argc, argv_ro, action, actarg)
113     client *cl;
114     char *name;
115     int argc;
116     char *argv_ro[];
117     int (*action)();
118     char *actarg;
119 {
120     register struct query *q;
121     register int status;
122     register struct validate *v;
123     char qual[256];
124     char sort[32];
125     char *pqual;
126     char *psort;
127 ##  char *table;
128     struct save_queue *sq;
129     struct query *get_query_by_name();
130     int sq_save_args();
131     struct save_queue *sq_create();
132     char *build_sort();
133
134     ingres_errno = 0;
135
136     /* list queries command */
137     if (!strcmp(name, "_list_queries")) {
138         list_queries(cl->args->sms_version_no, action, actarg);
139         return(SMS_SUCCESS);
140     }
141
142     /* help query command */
143     if (!strcmp(name, "_help")) {
144         if (argc < 1)
145             return(SMS_ARGS);
146         q = get_query_by_name(argv_ro[0], cl->args->sms_version_no);
147         if (q == (struct query *)0) return(SMS_NO_HANDLE);
148         help_query(q, action, actarg);
149         return(SMS_SUCCESS);
150     }
151
152     /* get query structure, return error if named query does not exist */
153     q = get_query_by_name(name, cl->args->sms_version_no);
154     if (q == (struct query *)0) return(SMS_NO_HANDLE);
155     v = q->validate;
156
157     if (q->type != RETRIEVE) {
158 ##      set lockmode session where readlock = exclusive
159 ##      begin transaction
160     }
161
162     /* setup argument vector, verify access and arguments */
163     if ((status = sms_verify_query(cl, q, argc, argv_ro)) != SMS_SUCCESS)
164         goto out;
165
166     /* perform any special query pre-processing */
167     if (v && v->pre_rtn) {
168         status = (*v->pre_rtn)(q, Argv, cl, 0);
169         if (status != SMS_SUCCESS)
170             goto out;
171     }
172
173     switch (q->type) {
174     case RETRIEVE:
175         /* for queries that do not permit wildcarding, check if row
176            uniquely exists */
177         if (v && v->field) {
178             status = validate_row(q, Argv, v);
179             if (status != SMS_EXISTS) break;
180         }
181
182         /* build "where" clause if needed */
183         if (q->qual) {
184             build_qual(q->qual, q->argc, Argv, qual);
185             pqual = qual;
186         } else {
187             pqual = 0;
188         }
189
190         /* build "sort" clause if needed */
191         if (v && v->valobj) {
192             psort = build_sort(v, sort);
193         } else {
194             psort = 0;
195         }
196
197         /* if there is a followup routine, then we must save the results */
198         /* of the first query for use by the followup routine */
199         /* if q->rvar = NULL, perform post_rtn only */
200         if (q->rvar) {
201             if (v && v->post_rtn) {
202                 sq = sq_create();
203                 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
204                 if (status != SMS_SUCCESS) {
205                     sq_destroy(sq);
206                     break;
207                 }
208                 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
209             } else {
210                 /* normal retrieve */
211                 status = do_retrieve(q, pqual, psort, action, actarg);
212             }
213             if (status != SMS_SUCCESS) break;
214         } else {
215             status = (*v->post_rtn)(q, Argv, cl, action, actarg);
216         }
217
218         break;
219
220     case UPDATE:
221         /* see if row already exists */
222         if (v->field) {
223             status = validate_row(q, Argv, v);
224             if (status != SMS_EXISTS) break;
225         }
226
227         /* build "where" clause and perform update */
228         /* if q->rvar = NULL, perform post_rtn only */
229         if (q->rvar) {
230             build_qual(q->qual, q->argc, Argv, qual);
231             status = do_update(q, &Argv[q->argc], qual, action, actarg);
232             if (status != SMS_SUCCESS) break;
233             table = q->rtable;
234             if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif")) {
235 ##              repeat replace tblstats (updates = tblstats.updates + 1,
236 ##                                       modtime = "now")
237 ##                  where tblstats.#table = @table
238             }
239         }
240
241         /* execute followup routine (if any) */
242         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
243
244         break;
245
246     case APPEND:
247         /* see if row already exists */
248         if (v->field) {
249             status = validate_row(q, Argv, v);
250             if (status != SMS_NO_MATCH) break;
251         }
252
253         /* increment id number if necessary */
254         if (v->object_id) {
255             status = set_next_object_id(v->object_id, q->rtable);
256             if (status != SMS_SUCCESS) break;
257         }
258
259         /* build "where" clause if needed */
260         if (q->qual) {
261             build_qual(q->qual, q->argc, Argv, qual);
262             pqual = qual;
263         } else {
264             pqual = 0;
265         }
266
267         /* perform the append */
268         /* if q->rvar = NULL, perform post_rtn only */
269         if (q->rvar) {
270             status = do_append(q, &Argv[q->argc], pqual, action, actarg);
271             if (status != SMS_SUCCESS) break;
272             table = q->rtable;
273 ##          repeat replace tblstats (appends = tblstats.appends + 1,
274 ##                                   modtime = "now")
275 ##              where tblstats.#table = @table
276         }
277         
278         /* execute followup routine */
279         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
280         break;
281
282     case DELETE:
283         /* see if row already exists */
284         if (v->field) {
285             status = validate_row(q, Argv, v);
286             if (status != SMS_EXISTS) break;
287         }
288
289         /* build "where" clause and perform delete */
290         /* if q->rvar = NULL, perform post_rtn only */
291         if (q->rvar) {
292             build_qual(q->qual, q->argc, Argv, qual);
293             status = do_delete(q, qual, action, actarg);
294             if (status != SMS_SUCCESS) break;
295             table = q->rtable;
296 ##          repeat replace tblstats (deletes = tblstats.deletes + 1,
297 ##                                   modtime = "now")
298 ##              where tblstats.#table = @table
299         }
300
301         /* execute followup routine */
302         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
303         break;
304
305     }
306
307 out:
308     if (q->type != RETRIEVE) {
309         if (status == SMS_SUCCESS) {
310 ##          end transaction     /* commit to this */
311             if (journal) {
312                 char buf[1024], *bp;
313                 int i;
314                 extern time_t now;
315
316                 fprintf(journal, "%% %s %s %s",
317                         cl->clname, cl->entity, ctime(&now));
318                 fprintf(journal, "%s[%d] ", q->name, cl->args->sms_version_no);
319                 for (i = 0; i < argc; i++) {
320                     if (i != 0) {
321                         putc(' ', journal);
322                     }
323                     requote(buf, argv_ro[i], sizeof(buf));
324                     fputs(buf, journal);
325                 }
326                 putc('\n', journal);
327                 fflush(journal);
328             }
329         } else {
330             if (ingres_errno != INGRES_DEADLOCK) {
331 ##              abort           /* it never happened */
332             }
333         }
334 ##      set lockmode session where readlock = system
335     }
336
337     if (status == SMS_SUCCESS && ingres_errno != 0) {
338         critical_alert("SMS", "Server didn't notice INGRES ERROR %d",
339                        ingres_errno);
340         status = SMS_INTERNAL;
341     }
342
343     if (status != SMS_SUCCESS && log_flags & LOG_RES)
344         com_err(whoami, status, " (Query failed)");
345     /* until all the clients know about SMS_BUSY, convert this error
346      * to one they will recognize.
347      */
348     if (status == SMS_BUSY)
349       status = SMS_DEADLOCK;
350     return(status);
351 }
352
353 build_qual(fmt, argc, argv, qual)
354         char *fmt;
355         int argc;
356         char *argv[];
357         char *qual;
358 {
359     register char *c;
360     register int i;
361     char *args[4];
362     char *index();
363
364     c = fmt;
365     for (i = 0; i < argc; i++) {
366         c = index(c, '%');
367         if (c++ == (char *)0) return(SMS_ARGS);
368         if (*c == 's')
369             args[i] = argv[i];
370         else if (*c == 'd')
371             *(int *)&args[i] = *(int *)argv[i]; /* sigh */
372         else
373             return(SMS_INGRES_ERR);
374     }
375
376     switch (argc) {
377     case 0:
378         strcpy(qual, fmt);
379         break;
380
381     case 1:
382         sprintf(qual, fmt, args[0]);
383         break;
384
385     case 2:
386         sprintf(qual, fmt, args[0], args[1]);
387         break;
388
389     case 3:
390         sprintf(qual, fmt, args[0], args[1], args[2]);
391         break;
392
393     case 4:
394         sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
395         break;
396     }
397     return(SMS_SUCCESS);
398 }
399
400 char *
401 build_sort(v, sort)
402     register struct validate *v;
403     char *sort;
404 {
405     register struct valobj *vo;
406     register int n;
407     char elem[16];
408
409     n = v->objcnt;
410     vo = v->valobj;
411     *sort = 0;
412
413     while (--n >= 0) {
414         if (vo->type == V_SORT) {
415             sprintf(elem, "RET_VAR%d", vo->index + 1);
416             if (*sort) strcat(sort, ", ");
417             strcat(sort, elem);
418         }
419         vo++;
420     }
421
422     return ((*sort) ? sort : 0);
423 }
424
425
426 /* Build arguement vector, verify query and arguments */
427
428 sms_verify_query(cl, q, argc, argv_ro)
429     client *cl;
430     struct query *q;
431     int argc;
432     char *argv_ro[];
433 {
434     register int argreq;
435     register int status;
436     register struct validate *v = q->validate;
437     register int i;
438     register int privileged = 0;
439     int len;
440
441     /* copy the arguments into a local argv that we can modify */
442     if (argc >= QMAXARGS)
443       return(SMS_ARGS);
444     for (i = 0; i < argc; i++) {
445         if ((len = strlen(argv_ro[i])) < ARGLEN)
446             strcpy(Argv[i], argv_ro[i]);
447         else
448             return(SMS_ARG_TOO_LONG);
449         if (Argv[i][len-1] == '\\')
450           return(SMS_BAD_CHAR);
451     }
452
453     /* check initial query access */
454     status = check_query_access(q, Argv, cl);
455     if (status != SMS_SUCCESS && status != SMS_PERM)
456         return(status);
457     if (status == SMS_SUCCESS)
458         privileged++;
459
460     /* check argument count */
461     argreq = q->argc;
462     if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
463     if (argc != argreq) return(SMS_ARGS);
464
465     /* validate arguments */
466     if (v && v->valobj) {
467         status = validate_fields(q, Argv, v->valobj, v->objcnt);
468         if (status != SMS_SUCCESS) return(status);
469     }
470
471     /* perform special query access check */
472     if (!privileged && v && v->acs_rtn) {
473         status = (*v->acs_rtn)(q, Argv, cl);
474         if (status != SMS_SUCCESS && status != SMS_PERM)
475             return(status);
476         if (status == SMS_SUCCESS)
477             privileged++;
478     }
479
480     return(privileged ? SMS_SUCCESS : SMS_PERM);
481 }
482
483 check_query_access(q, argv, cl)
484     struct query *q;
485     char *argv[];
486     client *cl;
487 ##{
488 ##  char *name;
489 ##  int acl_id;
490 ##  int exists;
491 ##  int rowcount;
492 ##  int errorno;
493 ##  static int def_uid;
494     int status;
495     int client_id;
496     char *client_type;
497
498     /* get query access control list */
499     name = q->shortname;
500 ##  repeat retrieve (acl_id = capacls.list_id) where capacls.tag = @name
501 ##  inquire_equel (rowcount = "rowcount", errorno = "errorno")
502     if (errorno != 0) return(SMS_INGRES_ERR);
503     if (rowcount == 0) return(SMS_PERM);
504
505     /* initialize default uid */
506     if (def_uid == 0) {
507 ##      retrieve (def_uid = users.users_id) where users.login = "default"
508     }
509
510     /* check for default access */
511 ##  range of m is members
512 ##  repeat retrieve (exists = any(m.#member_id where m.list_id = @acl_id and
513 ##                   m.member_type = "USER" and m.#member_id = def_uid))
514     if (exists) return(SMS_SUCCESS);
515
516     /* parse client name */
517     status = get_client(cl, &client_type, &client_id);
518     if (status != SMS_SUCCESS) return(status);
519
520     /* see if client is in the list (or any of its sub-lists) */
521     exists = find_member("LIST", acl_id, client_type, client_id, 0);
522     return ((exists) ? SMS_SUCCESS : SMS_PERM);
523 ##}
524
525 get_client(cl, client_type, client_id)
526     client *cl;
527     char **client_type;
528     int *client_id;
529 ##{
530     struct krbname *krb;
531 ##  int member_id;
532 ##  char *name;
533 ##  int rowcount;
534
535     if (cl->clname == NULL)
536         return SMS_PERM;
537     
538     /* for now ignore instances */
539     krb = &cl->kname;
540
541     /* if client is from local realm, get users_id */
542     if (!strcmp(krb->realm, krb_realm)) {
543         *client_id = cl->users_id;
544         *client_type = "USER";
545         return(SMS_SUCCESS);
546     }
547
548     /* otherwise use string_id */
549     name = cl->clname;
550 ##  repeat retrieve (member_id = strings.string_id) 
551 ##      where strings.string = @name
552         
553     /* make sure we found a users or string id */
554 ##  inquire_equel (rowcount = "rowcount")
555     if (rowcount == 0) return(SMS_PERM);
556
557     *client_type = "STRING";
558     *client_id = member_id;
559     return(SMS_SUCCESS);
560 ##}
561
562 ##find_member(list_type, list_id, member_type, member_id, sq)
563     char *list_type;
564 ##  int list_id;
565 ##  char *member_type;
566 ##  int member_id;
567     struct save_queue *sq;
568 ##{
569 ##  int exists;
570 ##  int sublist;
571     int child;
572     struct save_queue *sq_create();
573
574     if (!strcmp(strtrim(list_type), strtrim(member_type)) &&
575         list_id == member_id)
576         return(1);
577
578     /* see if client is a direct member of list */
579 ##  repeat retrieve (exists = any(m.#member_id where 
580 ##                                m.#list_id = @list_id and
581 ##                                m.#member_type = @member_type and 
582 ##                                m.#member_id = @member_id))
583     if (exists) return(1);
584
585     /* are there any sub-lists? */
586 ##  repeat retrieve (exists = any(m.#member_id where m.#list_id = @list_id and
587 ##                   m.#member_type = "LIST"))
588     if (!exists) return(0);
589
590     /* yes; now recurse through sublists */
591
592     /* create a save queue */
593     if (sq == (struct save_queue *)0) {
594         sq = sq_create();
595         child = 0;
596     } else {
597         child = 1;
598     }
599
600     /* save all sublist ids */
601 ##  range of m is members
602 ##  retrieve (sublist = m.#member_id) 
603 ##      where m.#list_id = list_id and m.#member_type = "LIST"
604 ##  {
605          sq_save_unique_data(sq, sublist);
606 ##  }
607
608     if (child) return(0);
609
610     /* at top-level, check sub-lists for client (breadth-first search) */
611     while (sq_get_data(sq, &sublist)) {
612         exists = find_member(list_type, sublist, member_type, member_id, sq);
613         if (exists) {
614             sq_destroy(sq);
615             return(1);
616         }
617     }
618     sq_destroy(sq);
619     return(0);
620 ##}
621
622
623 do_retrieve(q, pqual, psort, action, actarg)
624     register struct query *q;
625     char *pqual;
626     char *psort;
627     int (*action)();
628     char *actarg;
629 ##{
630 ##  char *rvar;
631 ##  char *rtable;
632 ##  char *cqual;
633 ##  char *csort;
634 ##  int rowcount;
635 ##  int errorno;
636     static char **vaddrs = (char **)NULL;
637
638     if (!vaddrs) {
639         register int i;
640
641         if ((vaddrs = (char **)malloc(sizeof(char *) * QMAXARGS)) == NULL) {
642             com_err(whoami, SMS_NO_MEM, "setting up static argv");
643             exit(1);
644         }
645         for (i = 0; i < QMAXARGS; i++) {
646             if ((vaddrs[i] = malloc(QMAXARGSIZE)) == NULL) {
647                 com_err(whoami, SMS_NO_MEM, "setting up static argv");
648                 exit(1);
649             }
650         }
651     }
652
653     if (q->rvar) {
654         rvar = q->rvar;
655         rtable = q->rtable;
656 ##      range of rvar is rtable
657     }
658
659     if (psort) {
660         csort = psort;
661         if (pqual) {
662             cqual = pqual;
663 ##          retrieve unique (param (q->tlist, vaddrs)) where cqual
664 ##                   sort by csort
665 ##          {
666                  (*action)(q->vcnt, vaddrs, actarg);
667 ##          }
668         } else {
669 ##          retrieve unique (param (q->tlist, vaddrs))
670 ##                   sort by csort
671 ##          {
672                  (*action)(q->vcnt, vaddrs, actarg);
673 ##          }
674         }
675
676     } else {
677         if (pqual) {
678             cqual = pqual;
679 ##          retrieve unique (param (q->tlist, vaddrs)) where cqual
680 ##          {
681                  (*action)(q->vcnt, vaddrs, actarg);
682 ##          }
683         } else {
684 ##          retrieve unique (param (q->tlist, vaddrs))
685 ##          {
686                  (*action)(q->vcnt, vaddrs, actarg);
687 ##          }
688         }
689     }
690
691 ##  inquire_equel (rowcount = "rowcount", errorno = "errorno")
692     if (errorno != 0) return(SMS_INGRES_ERR);
693     return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
694 ##}
695
696 do_update(q, argv, qual, action, actarg)
697     register struct query *q;
698     char *argv[];
699     char *qual;
700     int (*action)();
701     char *actarg;
702 ##{
703 ##  char *rvar;
704 ##  char *rtable;
705 ##  char *cqual;
706 ##  int errorno;
707       
708     rvar = q->rvar;
709     rtable = q->rtable;
710 ##  range of rvar is rtable
711
712     cqual = qual;
713 ##  replace rvar (param (q->tlist, argv))
714 ##  where cqual
715
716 ##  inquire_equel (errorno = "errorno")
717     if (errorno == INGRES_BAD_INT)
718         return(SMS_INTEGER);
719     else if (errorno != 0)
720         return(SMS_INGRES_ERR);
721     return(SMS_SUCCESS);
722 ##}
723
724 do_append(q, argv, pqual, action, actarg)
725     register struct query *q;
726     char *argv[];
727     char *pqual;
728     int (*action)();
729     char *actarg;
730 ##{
731 ##  char *rvar;
732 ##  char *rtable;
733 ##  char *cqual;
734 ##  int errorno;
735
736     rvar = q->rvar;
737     rtable = q->rtable;
738 ##  range of rvar is rtable
739
740     if (pqual) {
741         cqual = pqual;
742 ##      append to rtable (param (q->tlist, argv)) where cqual
743     } else {
744 ##      append to rtable (param (q->tlist, argv))
745     }
746
747 ##  inquire_equel (errorno = "errorno")
748     if (errorno == INGRES_BAD_INT)
749         return(SMS_INTEGER);
750     else if (errorno != 0)
751         return(SMS_INGRES_ERR);
752     return(SMS_SUCCESS);
753 ##}
754
755 do_delete(q, qual, action, actarg)
756     register struct query *q;
757     char *qual;
758     int (*action)();
759     char *actarg;
760 ##{
761 ##  char *rvar;
762 ##  char *rtable;
763 ##  char *cqual;
764 ##  int errorno;
765
766     rvar = q->rvar;
767     rtable = q->rtable;
768 ##  range of rvar is rtable
769
770     cqual = qual;
771 ##  delete rvar where cqual
772
773 ##  inquire_equel (errorno = "errorno")
774     if (errorno != 0) return(SMS_INGRES_ERR);
775     return(SMS_SUCCESS);
776 ##}
777
778
779 /**
780  ** set_next_object_id - set next object id in values table
781  **
782  ** Inputs: object - object name in values table and in objects
783  **         table - name of table objects are found in
784  **
785  ** - called before an APPEND operation to set the next object id to
786  **   be used for the new record to the next free value
787  **
788  **/
789
790 set_next_object_id(object, table)
791     char *object;
792     char *table;
793 ##{
794 ##  char *name, *tbl;
795 ##  int rowcount, exists, value;
796
797     name = object;
798     tbl = table;
799 ##  range of v is values
800 ##  repeat retrieve (value = v.#value) where v.#name = @name
801 ##  inquire_equel(rowcount = "rowcount")
802     if (rowcount != 1)
803         return(SMS_NO_ID);
804
805 ##  retrieve (exists = any(tbl.name where tbl.name = value))
806 ##  inquire_equel(rowcount = "rowcount")
807     if (rowcount != 1)
808         return(SMS_NO_ID);
809     while (exists) {
810         value++;
811         if (value > MAX_ID_VALUE)
812             value = MIN_ID_VALUE;
813 ##      retrieve (exists = any(tbl.name where tbl.name = value))
814     }
815
816     if (LOG_RES)
817         com_err(whoami, 0, "setting ID %s to %d", name, value);
818 ##  repeat replace v (#value = @value) where v.#name = @name
819     return(SMS_SUCCESS);
820 ##}
821
822
823 /* For now this just checks the argc's.  It should also see that there
824  * are no duplicate names.
825  */
826
827 sanity_check_queries()
828 {
829     register int i;
830     int maxv = 0, maxa = 0;
831 #ifdef MULTIPROTOCOLS
832     extern int QueryCount1, QueryCount2;
833     extern struct query Queries1[], Queries2[];
834 #else
835     extern int QueryCount2;
836     extern struct query Queries2[];
837 #endif MULTIPROTOCOLS
838
839 #define MAX(x,y) ((x) > (y) ? (x) : (y))
840
841 #ifdef MULTIPROTOCOLS
842     for (i = 0; i < QueryCount1; i++) {
843         maxv = MAX(maxv, Queries1[i].vcnt);
844         maxa = MAX(maxa, Queries1[i].argc);
845     }
846 #endif MULTIPROTOCOLS
847     for (i = 0; i < QueryCount2; i++) {
848         maxv = MAX(maxv, Queries2[i].vcnt);
849         maxa = MAX(maxa, Queries2[i].argc);
850     }
851     if (MAX(maxv, maxa) > QMAXARGS) {
852         com_err(whoami, 0, "A query has more args than QMAXARGS");
853         exit(1);
854     }
855 }
This page took 1.629007 seconds and 5 git commands to generate.