6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
9 * Revision 1.11 1987-09-01 16:10:01 wesommer
10 * This change was made by Mike, who didn't feel like checking it in.
11 * Temp hack: ignore instances.
13 * Revision 1.10 87/08/28 14:57:51 mike
14 * Modified sms_query to not enclose RETRIEVE queries in begin/end transaction.
15 * This was necessary to allow get_all_poboxes and get_groups_of_all_users
16 * to temporarily change the Ingres lockmode.
18 * Revision 1.9 87/08/22 17:47:38 wesommer
19 * Cleanup (these changes were by Mike).
21 * Revision 1.8 87/08/10 16:22:26 mike
22 * wesommer modified error reporting.
24 * Revision 1.7 87/08/04 01:49:20 wesommer
25 * Rearranged messages.
27 * Revision 1.6 87/08/04 01:30:54 wesommer
28 * Mike's changes; checked in prior to working over messages.
30 * Revision 1.5 87/06/21 16:37:58 wesommer
31 * Changed include files, reindented things.
34 * Revision 1.4 87/06/08 05:03:27 wesommer
35 * Reindented; added header and trailer.
40 static char *rcsid_qrtn_qc = "$Header$";
44 #include "sms_server.h"
50 static int ingres_errno = 0;
54 * ingerr: (supposedly) called when Ingres indicates an error.
55 * I have not yet been able to get this to work to intercept a
56 * database open error.
59 static int ingerr(num)
62 ingres_errno = SMS_INGRES_ERR;
63 com_err(whoami, SMS_INGRES_ERR, " code %d\n", ingres_errno);
67 int sms_open_database()
71 /* initialize local argv */
72 for (i = 0; i < 16; i++)
73 Argv[i] = (char *)malloc(128);
79 /* open the database */
84 int sms_close_database()
89 sms_check_access(cl, name, argc, argv_ro)
95 register struct query *q;
98 register struct validate *v;
100 register int privileged;
101 struct query *get_query_by_name();
106 q = get_query_by_name(name);
107 if (q == (struct query *)0) return(SMS_NO_HANDLE);
110 /* copy the arguments into a local argv that we can modify */
111 for (i = 0; i < argc; i++)
112 strcpy(Argv[i], argv_ro[i]);
114 /* check initial query access */
115 status = check_query_access(q, Argv, cl);
116 privileged = (status == SMS_SUCCESS) ? 1 : 0;
117 if (status != SMS_SUCCESS && !(v && (v->pre_rtn == access_user ||
118 v->pre_rtn == access_pop ||
119 v->pre_rtn == access_list)))
122 /* check argument count */
124 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
125 if (argc != argreq) return(SMS_ARGS);
127 /* validate arguments */
128 if (v && v->valobj) {
129 status = validate_fields(q, Argv, v->valobj, v->objcnt);
130 if (status != SMS_SUCCESS) return(status);
133 /* perform special query access check */
134 if (v && v->pre_rtn) {
135 status = (*v->pre_rtn)(q, Argv, cl, 1);
136 if (status != SMS_SUCCESS && (status != SMS_PERM || !privileged))
143 sms_process_query(cl, name, argc, argv_ro, action, actarg)
151 register struct query *q;
155 register struct validate *v;
162 struct save_queue *sq;
163 struct query *get_query_by_name();
165 struct save_queue *sq_create();
171 /* copy the arguments into a local argv that we can modify */
172 for (i = 0; i < argc; i++)
173 strcpy(Argv[i], argv_ro[i]);
175 /* list queries command */
176 if (!strcmp(name, "_list_queries")) {
177 list_queries(action, actarg);
181 /* help query command */
182 if (!strcmp(name, "_help")) {
183 q = get_query_by_name(Argv[0]);
184 if (q == (struct query *)0) return(SMS_NO_HANDLE);
185 help_query(q, action, actarg);
189 /* get query structure, return error if named query does not exist */
190 q = get_query_by_name(name);
191 if (q == (struct query *)0) return(SMS_NO_HANDLE);
194 /* check query access */
195 status = check_query_access(q, Argv, cl);
196 privileged = (status == SMS_SUCCESS) ? 1 : 0;
197 if (!privileged && !(status == SMS_PERM &&
198 (v && (v->pre_rtn == access_user ||
199 v->pre_rtn == access_pop ||
200 v->pre_rtn == access_list))))
203 /* check argument count */
205 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
206 if (argc != argreq) return(SMS_ARGS);
208 /* validate arguments */
209 if (v && v->valobj) {
210 status = validate_fields(q, Argv, v->valobj, v->objcnt);
211 if (status != SMS_SUCCESS) return(status);
214 /* perform any special query pre-processing */
215 if (v && v->pre_rtn) {
216 status = (*v->pre_rtn)(q, Argv, cl, 0);
217 if (status != SMS_SUCCESS && (status != SMS_PERM || !privileged))
221 if (q->type != RETRIEVE)
226 /* for queries that do not permit wildcarding, check if row
229 status = validate_row(q, Argv, v);
230 if (status != SMS_EXISTS) break;
233 /* build "where" clause if needed */
235 build_qual(q->qual, q->argc, Argv, qual);
241 /* build "sort" clause if needed */
242 if (v && v->valobj) {
243 psort = build_sort(v, sort);
248 /* if there is a followup routine, then we must save the results */
249 /* of the first query for use by the followup routine */
250 /* if q->rvar = NULL, perform post_rtn only */
252 if (v && v->post_rtn) {
254 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
255 if (status != SMS_SUCCESS) {
259 status = (*v->post_rtn)(q, sq, v, action, actarg);
261 /* normal retrieve */
262 status = do_retrieve(q, pqual, psort, action, actarg);
264 if (status != SMS_SUCCESS) break;
266 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
267 ## where tblstats.#table = @table
269 status = (*v->post_rtn)(q, Argv, action, actarg);
275 /* see if row already exists */
277 status = validate_row(q, Argv, v);
278 if (status != SMS_EXISTS) break;
281 /* build "where" clause and perform update */
282 /* if q->rvar = NULL, perform post_rtn only */
284 build_qual(q->qual, q->argc, Argv, qual);
285 status = do_update(q, &Argv[q->argc], qual, action, actarg);
286 if (status != SMS_SUCCESS) break;
288 ## repeat replace tblstats (updates = tblstats.updates + 1,
290 ## where tblstats.#table = @table
293 /* execute followup routine (if any) */
294 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
299 /* see if row already exists */
301 status = validate_row(q, Argv, v);
302 if (status != SMS_NO_MATCH) break;
305 /* increment id number if necessary */
306 if (v->object_id) set_next_object_id(v->object_id);
308 /* build "where" clause if needed */
310 build_qual(q->qual, q->argc, Argv, qual);
316 /* perform the append */
317 /* if q->rvar = NULL, perform post_rtn only */
319 status = do_append(q, &Argv[q->argc], pqual, action, actarg);
320 if (status != SMS_SUCCESS) break;
322 ## repeat replace tblstats (appends = tblstats.appends + 1,
324 ## where tblstats.#table = @table
327 /* execute followup routine */
328 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
332 /* see if row already exists */
334 status = validate_row(q, Argv, v);
335 if (status != SMS_EXISTS) break;
338 /* build "where" clause and perform delete */
339 /* if q->rvar = NULL, perform post_rtn only */
341 build_qual(q->qual, q->argc, Argv, qual);
342 status = do_delete(q, qual, action, actarg);
343 if (status != SMS_SUCCESS) break;
345 ## repeat replace tblstats (deletes = tblstats.deletes + 1,
347 ## where tblstats.#table = @table
350 /* execute followup routine */
351 if (v->post_rtn) status = (*v->post_rtn)(q, Argv);
356 if (q->type != RETRIEVE) {
357 if (status == SMS_SUCCESS) {
364 if (status != SMS_SUCCESS && log_flags & LOG_RES)
365 com_err(whoami, status, " (Query failed)");
369 build_qual(fmt, argc, argv, qual)
380 for (i = 0; i < argc; i++) {
381 c = (char *)index(c, '%');
382 if (c++ == (char *)0) return(SMS_ARGS);
386 *(int *)&args[i] = *(int *)argv[i]; /* sigh */
388 return(SMS_INGRES_ERR);
397 sprintf(qual, fmt, args[0]);
401 sprintf(qual, fmt, args[0], args[1]);
405 sprintf(qual, fmt, args[0], args[1], args[2]);
409 sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
416 register struct validate *v;
419 register struct valobj *vo;
428 if (vo->type == V_SORT) {
429 sprintf(elem, "RET_VAR%d", vo->index + 1);
430 if (*sort) strcat(sort, ", ");
436 return ((*sort) ? sort : 0);
439 check_query_access(q, argv, cl)
449 ## static int def_uid;
454 /* get query access control list */
456 ## repeat retrieve (acl_id = capacls.list_id) where capacls.tag = @name
457 ## inquire_equel (rowcount = "rowcount", errorno = "errorno")
458 if (errorno != 0) return(SMS_INGRES_ERR);
459 if (rowcount == 0) return(SMS_PERM);
461 /* initialize default uid */
463 ## retrieve (def_uid = users.users_id) where users.login = "default"
466 /* check for default access */
467 ## range of m is members
468 ## repeat retrieve (exists = any(m.#member_id where m.list_id = @acl_id and
469 ## m.member_type = "USER" and m.#member_id = def_uid))
470 if (exists) return(SMS_SUCCESS);
472 /* parse client name */
473 status = get_client(cl, &client_type, &client_id);
474 if (status != SMS_SUCCESS) return(status);
476 /* see if client is in the list (or any of its sub-lists) */
477 exists = find_member(acl_id, client_type, client_id, 0);
478 return ((exists) ? SMS_SUCCESS : SMS_PERM);
481 get_client(cl, client_type, client_id)
491 /* for now ignore instances */
494 /* if client is from local realm, get users_id */
495 if (!strcmp(krb->realm, krb_realm)) {
497 ## repeat retrieve (member_id = users.users_id) where users.login = @name
498 *client_type = "USER";
500 /* otherwise use string_id */
502 ## repeat retrieve (member_id = strings.string_id)
503 ## where strings.string = @name
504 *client_type = "STRING";
507 /* make sure we found a users or string id */
508 ## inquire_equel (rowcount = "rowcount")
509 if (rowcount == 0) return(SMS_PERM);
511 *client_id = member_id;
515 ##find_member(list_id, member_type, member_id, sq)
517 ## char *member_type;
519 struct save_queue *sq;
524 struct save_queue *sq_create();
526 /* see if client is a direct member of list */
527 ## repeat retrieve (exists = any(m.#member_id where
528 ## m.#list_id = @list_id and
529 ## m.#member_type = @member_type and
530 ## m.#member_id = @member_id))
531 if (exists) return(1);
533 /* are there any sub-lists? */
534 ## repeat retrieve (exists = any(m.#member_id where m.#list_id = @list_id and
535 ## m.#member_type = "LIST"))
536 if (!exists) return(0);
538 /* yes; now recurse through sublists */
540 /* create a save queue */
541 if (sq == (struct save_queue *)0) {
548 /* save all sublist ids */
549 ## range of m is members
550 ## retrieve (sublist = m.#member_id)
551 ## where m.#list_id = list_id and m.#member_type = "LIST"
553 sq_save_unique_data(sq, sublist);
558 /* at top-level, check sub-lists for client (breadth-first search) */
559 while (sq_get_data(sq, &sublist)) {
560 exists = find_member(sublist, member_type, member_id, sq);
568 do_retrieve(q, pqual, psort, action, actarg)
569 register struct query *q;
585 ## range of rvar is rtable
592 ## retrieve unique (param (q->tlist, q->vaddr)) where cqual
595 (*action)(q->vcnt, q->vaddr, actarg);
598 ## retrieve unique (param (q->tlist, q->vaddr))
601 (*action)(q->vcnt, q->vaddr, actarg);
608 ## retrieve unique (param (q->tlist, q->vaddr)) where cqual
610 (*action)(q->vcnt, q->vaddr, actarg);
613 ## retrieve unique (param (q->tlist, q->vaddr))
615 (*action)(q->vcnt, q->vaddr, actarg);
620 ## inquire_equel (rowcount = "rowcount", errorno = "errorno")
621 if (errorno != 0) return(SMS_INGRES_ERR);
622 return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
625 do_update(q, argv, qual, action, actarg)
626 register struct query *q;
640 ## range of rvar is rtable
643 ## replace rvar (param (q->tlist, argv))
646 ## inquire_equel (errorno = "errorno")
647 if (errorno != 0) return(SMS_INGRES_ERR);
651 do_append(q, argv, pqual, action, actarg)
652 register struct query *q;
665 ## range of rvar is rtable
669 ## append to rtable (param (q->tlist, argv)) where cqual
671 ## append to rtable (param (q->tlist, argv))
674 ## inquire_equel (errorno = "errorno")
675 if (errorno != 0) return(SMS_INGRES_ERR);
679 do_delete(q, qual, action, actarg)
680 register struct query *q;
692 ## range of rvar is rtable
695 ## delete rvar where cqual
697 ## inquire_equel (errorno = "errorno")
698 if (errorno != 0) return(SMS_INGRES_ERR);
707 * c-continued-statement-offset: 4
709 * c-argdecl-indent: 4