]> andersk Git - moira.git/blob - server/qrtn.qc
Modified sms_query to not enclose RETRIEVE queries in begin/end transaction.
[moira.git] / server / qrtn.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      $Log$
9  *      Revision 1.10  1987-08-28 14:57:51  mike
10  *      Modified sms_query to not enclose RETRIEVE queries in begin/end transaction.
11  *      This was necessary to allow get_all_poboxes and get_groups_of_all_users
12  *      to temporarily change the Ingres lockmode.
13  *
14  * Revision 1.9  87/08/22  17:47:38  wesommer
15  * Cleanup (these changes were by Mike).
16  * 
17  * Revision 1.8  87/08/10  16:22:26  mike
18  * wesommer modified error reporting.
19  * 
20  * Revision 1.7  87/08/04  01:49:20  wesommer
21  * Rearranged messages.
22  * 
23  * Revision 1.6  87/08/04  01:30:54  wesommer
24  * Mike's changes; checked in prior to working over messages.
25  * 
26  * Revision 1.5  87/06/21  16:37:58  wesommer
27  * Changed include files, reindented things.
28  * 
29  * 
30  * Revision 1.4  87/06/08  05:03:27  wesommer
31  * Reindented; added header and trailer.
32  * 
33  */
34
35 #ifndef lint
36 static char *rcsid_qrtn_qc = "$Header$";
37 #endif lint
38
39 #include "query.h"
40 #include "sms_server.h"
41
42 #define SMS_SUCCESS 0
43
44 char *Argv[16];
45
46 static int ingres_errno = 0;
47 extern char *whoami;
48
49 /*
50  * ingerr: (supposedly) called when Ingres indicates an error.
51  * I have not yet been able to get this to work to intercept a
52  * database open error.
53  */
54
55 static int ingerr(num)
56     int *num;
57 {
58     ingres_errno = SMS_INGRES_ERR;
59     com_err(whoami, SMS_INGRES_ERR, " code %d\n", ingres_errno);
60     return *num;
61 }
62
63 int sms_open_database()
64 {
65     register int i;
66
67     /* initialize local argv */
68     for (i = 0; i < 16; i++)
69         Argv[i] = (char *)malloc(128);
70
71     IIseterr(ingerr);
72         
73     ingres_errno = 0;
74         
75     /* open the database */
76 ##  ingres sms
77     return ingres_errno;
78 }
79
80 int sms_close_database()
81 {
82 ##  exit
83 }
84
85 sms_check_access(cl, name, argc, argv_ro)
86     client *cl;
87     char *name;
88     int argc;
89     char *argv_ro[];
90 {
91     register struct query *q;
92     register int argreq;
93     register int status;
94     register struct validate *v;
95     register int i;
96     register int privileged;
97     struct query *get_query_by_name();
98     int access_user();
99     int access_pop();
100     int access_list();
101
102     q = get_query_by_name(name);
103     if (q == (struct query *)0) return(SMS_NO_HANDLE);
104     v = q->validate;
105
106     /* copy the arguments into a local argv that we can modify */
107     for (i = 0; i < argc; i++)
108         strcpy(Argv[i], argv_ro[i]);
109
110     /* check initial query access */
111     status = check_query_access(q, Argv, cl);
112     privileged = (status == SMS_SUCCESS) ? 1 : 0;
113     if (status != SMS_SUCCESS && !(v && (v->pre_rtn == access_user ||
114                                          v->pre_rtn == access_pop ||
115                                          v->pre_rtn == access_list))) 
116         return(status);
117
118     /* check argument count */
119     argreq = q->argc;
120     if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
121     if (argc != argreq) return(SMS_ARGS);
122
123     /* validate arguments */
124     if (v && v->valobj) {
125         status = validate_fields(q, Argv, v->valobj, v->objcnt);
126         if (status != SMS_SUCCESS) return(status);
127     }
128
129     /* perform special query access check */
130     if (v && v->pre_rtn) {
131         status = (*v->pre_rtn)(q, Argv, cl, 1);
132         if (status != SMS_SUCCESS && (status != SMS_PERM || !privileged)) 
133             return(status);
134     }
135
136     return(SMS_SUCCESS);
137 }
138
139 sms_process_query(cl, name, argc, argv_ro, action, actarg)
140     client *cl;
141     char *name;
142     int argc;
143     char *argv_ro[];
144     int (*action)();
145     char *actarg;
146 {
147     register struct query *q;
148     register int i;
149     register int status;
150     register int argreq;
151     register struct validate *v;
152     int privileged;
153     char qual[256];
154     char sort[32];
155     char *pqual;
156     char *psort;
157 ##  char *table;
158     struct save_queue *sq;
159     struct query *get_query_by_name();
160     int sq_save_args();
161     struct save_queue *sq_create();
162     char *build_sort();
163     int access_user();
164     int access_pop();
165     int access_list();
166
167     /* copy the arguments into a local argv that we can modify */
168     for (i = 0; i < argc; i++)
169         strcpy(Argv[i], argv_ro[i]);
170
171     /* list queries command */
172     if (!strcmp(name, "_list_queries")) {
173         list_queries(action, actarg);
174         return(SMS_SUCCESS);
175     }
176
177     /* help query command */
178     if (!strcmp(name, "_help")) {
179         q = get_query_by_name(Argv[0]);
180         if (q == (struct query *)0) return(SMS_NO_HANDLE);
181         help_query(q, action, actarg);
182         return(SMS_SUCCESS);
183     }
184
185     /* get query structure, return error if named query does not exist */
186     q = get_query_by_name(name);
187     if (q == (struct query *)0) return(SMS_NO_HANDLE);
188     v = q->validate;
189
190     /* check query access */
191     status = check_query_access(q, Argv, cl);
192     privileged = (status == SMS_SUCCESS) ? 1 : 0;
193     if (!privileged && !(status == SMS_PERM &&
194                          (v && (v->pre_rtn == access_user ||
195                                 v->pre_rtn == access_pop ||
196                                 v->pre_rtn == access_list))))
197         return(status);
198
199     /* check argument count */
200     argreq = q->argc;
201     if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
202     if (argc != argreq) return(SMS_ARGS);
203
204     /* validate arguments */
205     if (v && v->valobj) {
206         status = validate_fields(q, Argv, v->valobj, v->objcnt);
207         if (status != SMS_SUCCESS) return(status);
208     }
209
210     /* perform any special query pre-processing */
211     if (v && v->pre_rtn) {
212         status = (*v->pre_rtn)(q, Argv, cl, 0);
213         if (status != SMS_SUCCESS && (status != SMS_PERM || !privileged))
214             return(status);
215     }
216
217     if (q->type != RETRIEVE)
218 ##      begin transaction
219
220     switch (q->type) {
221     case RETRIEVE:
222         /* for queries that do not permit wildcarding, check if row
223            uniquely exists */
224         if (v && v->field) {
225             status = validate_row(q, Argv, v);
226             if (status != SMS_EXISTS) break;
227         }
228
229         /* build "where" clause if needed */
230         if (q->qual) {
231             build_qual(q->qual, q->argc, Argv, qual);
232             pqual = qual;
233         } else {
234             pqual = 0;
235         }
236
237         /* build "sort" clause if needed */
238         if (v && v->valobj) {
239             psort = build_sort(v, sort);
240         } else {
241             psort = 0;
242         }
243
244         /* if there is a followup routine, then we must save the results */
245         /* of the first query for use by the followup routine */
246         /* if q->rvar = NULL, perform post_rtn only */
247         if (q->rvar) {
248             if (v && v->post_rtn) {
249                 sq = sq_create();
250                 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
251                 if (status != SMS_SUCCESS) {
252                     sq_destroy(sq);
253                     break;
254                 }
255                 status = (*v->post_rtn)(q, sq, v, action, actarg);
256             } else {
257                 /* normal retrieve */
258                 status = do_retrieve(q, pqual, psort, action, actarg);
259             }
260             if (status != SMS_SUCCESS) break;
261             table = q->rtable;
262 ##          repeat replace tblstats (retrieves = tblstats.retrieves + 1)
263 ##                 where tblstats.#table = @table
264         } else {
265             status = (*v->post_rtn)(q, Argv, action, actarg);
266         }
267
268         break;
269
270     case UPDATE:
271         /* see if row already exists */
272         if (v->field) {
273             status = validate_row(q, Argv, v);
274             if (status != SMS_EXISTS) break;
275         }
276
277         /* build "where" clause and perform update */
278         /* if q->rvar = NULL, perform post_rtn only */
279         if (q->rvar) {
280             build_qual(q->qual, q->argc, Argv, qual);
281             status = do_update(q, &Argv[q->argc], qual, action, actarg);
282             if (status != SMS_SUCCESS) break;
283             table = q->rtable;
284 ##          repeat replace tblstats (updates = tblstats.updates + 1,
285 ##                                   modtime = "now")
286 ##              where tblstats.#table = @table
287         }
288
289         /* execute followup routine (if any) */
290         if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
291
292         break;
293
294     case APPEND:
295         /* see if row already exists */
296         if (v->field) {
297             status = validate_row(q, Argv, v);
298             if (status != SMS_NO_MATCH) break;
299         }
300
301         /* increment id number if necessary */
302         if (v->object_id) set_next_object_id(v->object_id);
303
304         /* build "where" clause if needed */
305         if (q->qual) {
306             build_qual(q->qual, q->argc, Argv, qual);
307             pqual = qual;
308         } else {
309             pqual = 0;
310         }
311
312         /* perform the append */
313         /* if q->rvar = NULL, perform post_rtn only */
314         if (q->rvar) {
315             status = do_append(q, &Argv[q->argc], pqual, action, actarg);
316             if (status != SMS_SUCCESS) break;
317             table = q->rtable;
318 ##          repeat replace tblstats (appends = tblstats.appends + 1,
319 ##                                   modtime = "now")
320 ##              where tblstats.#table = @table
321         }
322         
323         /* execute followup routine */
324         if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
325         break;
326
327     case DELETE:
328         /* see if row already exists */
329         if (v->field) {
330             status = validate_row(q, Argv, v);
331             if (status != SMS_EXISTS) break;
332         }
333
334         /* build "where" clause and perform delete */
335         /* if q->rvar = NULL, perform post_rtn only */
336         if (q->rvar) {
337             build_qual(q->qual, q->argc, Argv, qual);
338             status = do_delete(q, qual, action, actarg);
339             if (status != SMS_SUCCESS) break;
340             table = q->rtable;
341 ##          repeat replace tblstats (deletes = tblstats.deletes + 1,
342 ##                                   modtime = "now")
343 ##              where tblstats.#table = @table
344         }
345
346         /* execute followup routine */
347         if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
348         break;
349
350     }
351
352     if (q->type != RETRIEVE) {
353         if (status == SMS_SUCCESS) {
354 ##          end transaction
355         } else {
356 ##          abort
357         }
358     }
359
360     if (status != SMS_SUCCESS && log_flags & LOG_RES)
361         com_err(whoami, status, " (Query failed)");
362     return(status);
363 }
364
365 build_qual(fmt, argc, argv, qual)
366         char *fmt;
367         int argc;
368         char *argv[];
369         char *qual;
370 {
371     register char *c;
372     register int i;
373     char *args[4];
374
375     c = fmt;
376     for (i = 0; i < argc; i++) {
377         c = (char *)index(c, '%');
378         if (c++ == (char *)0) return(SMS_ARGS);
379         if (*c == 's')
380             args[i] = argv[i];
381         else if (*c == 'd')
382             *(int *)&args[i] = *(int *)argv[i]; /* sigh */
383         else
384             return(SMS_INGRES_ERR);
385     }
386
387     switch (argc) {
388     case 0:
389         strcpy(qual, fmt);
390         break;
391
392     case 1:
393         sprintf(qual, fmt, args[0]);
394         break;
395
396     case 2:
397         sprintf(qual, fmt, args[0], args[1]);
398         break;
399
400     case 3:
401         sprintf(qual, fmt, args[0], args[1], args[2]);
402         break;
403
404     case 4:
405         sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
406         break;
407     }
408 }
409
410 char *
411 build_sort(v, sort)
412     register struct validate *v;
413     char *sort;
414 {
415     register struct valobj *vo;
416     register int n;
417     char elem[16];
418
419     n = v->objcnt;
420     vo = v->valobj;
421     *sort = 0;
422
423     while (--n >= 0) {
424         if (vo->type == V_SORT) {
425             sprintf(elem, "RET_VAR%d", vo->index + 1);
426             if (*sort) strcat(sort, ", ");
427             strcat(sort, elem);
428         }
429         vo++;
430     }
431
432     return ((*sort) ? sort : 0);
433 }
434
435 check_query_access(q, argv, cl)
436     struct query *q;
437     char *argv[];
438     client *cl;
439 ##{
440 ##  char *name;
441 ##  int acl_id;
442 ##  int exists;
443 ##  int rowcount;
444 ##  int errorno;
445 ##  static int def_uid;
446     int status;
447     int client_id;
448     char *client_type;
449
450     /* get query access control list */
451     name = q->shortname;
452 ##  repeat retrieve (acl_id = capacls.list_id) where capacls.tag = @name
453 ##  inquire_equel (rowcount = "rowcount", errorno = "errorno")
454     if (errorno != 0) return(SMS_INGRES_ERR);
455     if (rowcount == 0) return(SMS_PERM);
456
457     /* initialize default uid */
458     if (def_uid == 0) {
459 ##      retrieve (def_uid = users.users_id) where users.login = "default"
460     }
461
462     /* check for default access */
463 ##  range of m is members
464 ##  repeat retrieve (exists = any(m.#member_id where m.list_id = @acl_id and
465 ##                   m.member_type = "USER" and m.#member_id = def_uid))
466     if (exists) return(SMS_SUCCESS);
467
468     /* parse client name */
469     status = get_client(cl, &client_type, &client_id);
470     if (status != SMS_SUCCESS) return(status);
471
472     /* see if client is in the list (or any of its sub-lists) */
473     exists = find_member(acl_id, client_type, client_id, 0);
474     return ((exists) ? SMS_SUCCESS : SMS_PERM);
475 ##}
476
477 get_client(cl, client_type, client_id)
478     client *cl;
479     char **client_type;
480     int *client_id;
481 ##{
482     struct krbname *krb;
483 ##  int member_id;
484 ##  char *name;
485 ##  int rowcount;
486
487     /* for now accept only null instances */
488     krb = &cl->kname;
489     if (krb->inst[0]) return(SMS_PERM);
490
491     /* if client is from local realm, get users_id */
492     if (!strcmp(krb->realm, krb_realm)) {
493         name = krb->name;
494 ##      repeat retrieve (member_id = users.users_id) where users.login = @name
495         *client_type = "USER";
496     } else {
497         /* otherwise use string_id */
498         name = cl->clname;
499 ##      repeat retrieve (member_id = strings.string_id) 
500 ##          where strings.string = @name
501         *client_type = "STRING";
502     }
503         
504     /* make sure we found a users or string id */
505 ##  inquire_equel (rowcount = "rowcount")
506     if (rowcount == 0) return(SMS_PERM);
507
508     *client_id = member_id;
509     return(SMS_SUCCESS);
510 ##}
511
512 ##find_member(list_id, member_type, member_id, sq)
513 ##  int list_id;
514 ##  char *member_type;
515 ##  int member_id;
516     struct save_queue *sq;
517 ##{
518 ##  int exists;
519 ##  int sublist;
520     int child;
521     struct save_queue *sq_create();
522
523     /* see if client is a direct member of list */
524 ##  repeat retrieve (exists = any(m.#member_id where 
525 ##                                m.#list_id = @list_id and
526 ##                                m.#member_type = @member_type and 
527 ##                                m.#member_id = @member_id))
528     if (exists) return(1);
529
530     /* are there any sub-lists? */
531 ##  repeat retrieve (exists = any(m.#member_id where m.#list_id = @list_id and
532 ##                   m.#member_type = "LIST"))
533     if (!exists) return(0);
534
535     /* yes; now recurse through sublists */
536
537     /* create a save queue */
538     if (sq == (struct save_queue *)0) {
539         sq = sq_create();
540         child = 0;
541     } else {
542         child = 1;
543     }
544
545     /* save all sublist ids */
546 ##  range of m is members
547 ##  retrieve (sublist = m.#member_id) 
548 ##      where m.#list_id = list_id and m.#member_type = "LIST"
549 ##  {
550          sq_save_unique_data(sq, sublist);
551 ##  }
552
553     if (child) return;
554
555     /* at top-level, check sub-lists for client (breadth-first search) */
556     while (sq_get_data(sq, &sublist)) {
557         exists = find_member(sublist, member_type, member_id, sq);
558         if (exists) {
559             sq_destroy(sq);
560             return(1);
561         }
562     }
563 ##}
564
565 do_retrieve(q, pqual, psort, action, actarg)
566     register struct query *q;
567     char *pqual;
568     char *psort;
569     int (*action)();
570     char *actarg;
571 ##{
572 ##  char *rvar;
573 ##  char *rtable;
574 ##  char *cqual;
575 ##  char *csort;
576 ##  int rowcount;
577 ##  int errorno;
578
579     if (q->rvar) {
580         rvar = q->rvar;
581         rtable = q->rtable;
582 ##      range of rvar is rtable
583     }
584
585     if (psort) {
586         csort = psort;
587         if (pqual) {
588             cqual = pqual;
589 ##          retrieve unique (param (q->tlist, q->vaddr)) where cqual
590 ##                   sort by csort
591 ##          {
592                  (*action)(q->vcnt, q->vaddr, actarg);
593 ##          }
594         } else {
595 ##          retrieve unique (param (q->tlist, q->vaddr))
596 ##                   sort by csort
597 ##          {
598                  (*action)(q->vcnt, q->vaddr, actarg);
599 ##          }
600         }
601
602     } else {
603         if (pqual) {
604             cqual = pqual;
605 ##          retrieve unique (param (q->tlist, q->vaddr)) where cqual
606 ##          {
607                  (*action)(q->vcnt, q->vaddr, actarg);
608 ##          }
609         } else {
610 ##          retrieve unique (param (q->tlist, q->vaddr))
611 ##          {
612                  (*action)(q->vcnt, q->vaddr, actarg);
613 ##          }
614         }
615     }
616
617 ##  inquire_equel (rowcount = "rowcount", errorno = "errorno")
618     if (errorno != 0) return(SMS_INGRES_ERR);
619     return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
620 ##}
621
622 do_update(q, argv, qual, action, actarg)
623     register struct query *q;
624     char *argv[];
625     char *qual;
626     int (*action)();
627     char *actarg;
628 ##{
629 ##  char *rvar;
630 ##  char *rtable;
631 ##  char *cqual;
632 ##  int rowcount;
633 ##  int errorno;
634       
635     rvar = q->rvar;
636     rtable = q->rtable;
637 ##  range of rvar is rtable
638
639     cqual = qual;
640 ##  replace rvar (param (q->tlist, argv))
641 ##  where cqual
642
643 ##  inquire_equel (errorno = "errorno")
644     if (errorno != 0) return(SMS_INGRES_ERR);
645     return(SMS_SUCCESS);
646 ##}
647
648 do_append(q, argv, pqual, action, actarg)
649     register struct query *q;
650     char *argv[];
651     char *pqual;
652     int (*action)();
653     char *actarg;
654 ##{
655 ##  char *rvar;
656 ##  char *rtable;
657 ##  char *cqual;
658 ##  int errorno;
659
660     rvar = q->rvar;
661     rtable = q->rtable;
662 ##  range of rvar is rtable
663
664     if (pqual) {
665         cqual = pqual;
666 ##      append to rtable (param (q->tlist, argv)) where cqual
667     } else {
668 ##      append to rtable (param (q->tlist, argv))
669     }
670
671 ##  inquire_equel (errorno = "errorno")
672     if (errorno != 0) return(SMS_INGRES_ERR);
673     return(SMS_SUCCESS);
674 ##}
675
676 do_delete(q, qual, action, actarg)
677     register struct query *q;
678     char *qual;
679     int (*action)();
680     char *actarg;
681 ##{
682 ##  char *rvar;
683 ##  char *rtable;
684 ##  char *cqual;
685 ##  int errorno;
686
687     rvar = q->rvar;
688     rtable = q->rtable;
689 ##  range of rvar is rtable
690
691     cqual = qual;
692 ##  delete rvar where cqual
693
694 ##  inquire_equel (errorno = "errorno")
695     if (errorno != 0) return(SMS_INGRES_ERR);
696     return(SMS_SUCCESS);
697 ##}
698
699
700 /*
701  * Local Variables:
702  * mode: c
703  * c-indent-level: 4
704  * c-continued-statement-offset: 4
705  * c-brace-offset: -4
706  * c-argdecl-indent: 4
707  * c-label-offset: -4
708  * End:
709  */
710
This page took 1.321185 seconds and 5 git commands to generate.