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