6 * Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qrtn_qc = "$Header$";
16 #include <mit-copyright.h>
18 #include "mr_server.h"
24 ## int query_timeout = 30;
28 #define INGRES_BAD_INT 4111
29 #define INGRES_BAD_DATE 4302
30 #define INGRES_DEADLOCK 4700
31 #define INGRES_TIMEOUT 4702
32 #define INGRES_NO_RANGE 2109
35 * ingerr: (supposedly) called when Ingres indicates an error.
36 * I have not yet been able to get this to work to intercept a
37 * database open error.
40 static int ingerr(num)
47 mr_errcode = MR_INTEGER;
53 mr_errcode = MR_DEADLOCK;
54 com_err(whoami, 0, "INGRES deadlock detected");
58 com_err(whoami, 0, "timed out getting lock");
61 mr_errcode = MR_INGRES_SOFTFAIL;
62 com_err(whoami, 0, "INGRES missing range statement");
65 mr_errcode = MR_INGRES_ERR;
66 com_err(whoami, MR_INGRES_ERR, " code %d\n", *num);
67 critical_alert("MOIRA", "Moira server encountered INGRES ERROR %d", *num);
73 int mr_open_database()
77 static first_open = 1;
82 /* initialize local argv */
83 for (i = 0; i < 16; i++)
84 Argv[i] = malloc(ARGLEN);
94 /* open the database */
96 ## set lockmode session where level = table, timeout = query_timeout
97 ## set lockmode on capacls where readlock = shared
98 ## set lockmode on alias where readlock = shared
102 int mr_close_database()
108 mr_check_access(cl, name, argc, argv_ro)
115 struct query *get_query_by_name();
120 q = get_query_by_name(name, cl->args->mr_version_no);
121 if (q == (struct query *)0)
122 return(MR_NO_HANDLE);
124 return(mr_verify_query(cl, q, argc, argv_ro));
127 mr_process_query(cl, name, argc, argv_ro, action, actarg)
135 register struct query *q;
137 register struct validate *v;
142 ## char *table, *rvar;
143 struct save_queue *sq;
144 struct query *get_query_by_name();
146 struct save_queue *sq_create();
152 /* list queries command */
153 if (!strcmp(name, "_list_queries")) {
154 list_queries(cl->args->mr_version_no, action, actarg);
158 /* help query command */
159 if (!strcmp(name, "_help")) {
162 q = get_query_by_name(argv_ro[0], cl->args->mr_version_no);
163 if (q == (struct query *)0) return(MR_NO_HANDLE);
164 help_query(q, action, actarg);
168 /* get query structure, return error if named query does not exist */
169 q = get_query_by_name(name, cl->args->mr_version_no);
170 if (q == (struct query *)0) return(MR_NO_HANDLE);
173 if (q->type != RETRIEVE) {
177 /* setup argument vector, verify access and arguments */
178 if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
181 /* perform any special query pre-processing */
182 if (v && v->pre_rtn) {
183 status = (*v->pre_rtn)(q, Argv, cl, 0);
184 if (status != MR_SUCCESS)
190 /* for queries that do not permit wildcarding, check if row
193 status = validate_row(q, Argv, v);
194 if (status != MR_EXISTS) break;
197 /* build "where" clause if needed */
199 build_qual(q->qual, q->argc, Argv, qual);
205 /* build "sort" clause if needed */
206 if (v && v->valobj) {
207 psort = build_sort(v, sort);
212 /* if there is a followup routine, then we must save the results */
213 /* of the first query for use by the followup routine */
214 /* if q->rvar = NULL, perform post_rtn only */
216 if (v && v->post_rtn) {
218 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
219 if (status != MR_SUCCESS) {
223 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
225 /* normal retrieve */
226 status = do_retrieve(q, pqual, psort, action, actarg);
228 if (status != MR_SUCCESS) break;
230 status = (*v->post_rtn)(q, Argv, cl, action, actarg);
236 /* see if row already exists */
238 status = validate_row(q, Argv, v);
239 if (status != MR_EXISTS) break;
242 /* build "where" clause and perform update */
243 /* if q->rvar = NULL, perform post_rtn only */
245 build_qual(q->qual, q->argc, Argv, qual);
246 incremental_before(q->rtable, qual, argv_ro);
247 status = do_update(q, &Argv[q->argc], qual, action, actarg);
248 incremental_after(q->rtable, qual, argv_ro);
249 if (status != MR_SUCCESS) break;
250 flush_name(argv_ro[0], q->rtable);
252 if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif")) {
253 ## repeat replace tblstats (updates = tblstats.updates + 1,
255 ## where tblstats.#table = @table
259 /* execute followup routine (if any) */
260 if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
265 /* see if row already exists */
267 status = validate_row(q, Argv, v);
268 if (status != MR_NO_MATCH) break;
271 /* increment id number if necessary */
273 status = set_next_object_id(v->object_id, q->rtable);
274 if (status != MR_SUCCESS) break;
277 /* build "where" clause if needed */
279 build_qual(q->qual, q->argc, Argv, qual);
285 /* perform the append */
286 /* if q->rvar = NULL, perform post_rtn only */
288 incremental_clear_before();
289 status = do_append(q, &Argv[q->argc], pqual, action, actarg);
290 if (status != MR_SUCCESS) break;
291 if (v && v->object_id) {
292 sprintf(qual, "%s.%s = values.value and values.name = \"%s\"",
293 q->rvar, v->object_id, v->object_id);
294 incremental_after(q->rtable, qual, argv_ro);
296 incremental_after(q->rtable, pqual, argv_ro);
299 ## repeat replace tblstats (appends = tblstats.appends + 1,
301 ## where tblstats.#table = @table
304 /* execute followup routine */
305 if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
309 /* see if row already exists */
311 status = validate_row(q, Argv, v);
312 if (status != MR_EXISTS) break;
315 /* build "where" clause and perform delete */
316 /* if q->rvar = NULL, perform post_rtn only */
318 build_qual(q->qual, q->argc, Argv, qual);
321 ## range of rvar is table
322 incremental_before(q->rtable, qual, argv_ro);
323 status = do_delete(q, qual, action, actarg);
324 incremental_clear_after();
325 if (status != MR_SUCCESS) break;
326 flush_name(argv_ro[0], q->rtable);
327 ## repeat replace tblstats (deletes = tblstats.deletes + 1,
329 ## where tblstats.#table = @table
332 /* execute followup routine */
333 if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
339 if (status == MR_SUCCESS && ingres_errno != 0) {
340 com_err(whoami, MR_INTERNAL, "Server didn't notice INGRES ERROR %d",
345 if (q->type != RETRIEVE) {
346 if (status == MR_SUCCESS) {
347 ## end transaction /* commit to this */
353 fprintf(journal, "%% %s %s %s",
354 cl->clname, cl->entity, ctime(&now));
355 fprintf(journal, "%s[%d] ", q->name, cl->args->mr_version_no);
356 for (i = 0; i < argc; i++) {
360 requote(buf, argv_ro[i], sizeof(buf));
366 incremental_update();
368 if (ingres_errno != INGRES_DEADLOCK) {
369 ## abort /* it never happened */
373 ## set lockmode session where readlock = system
376 if (status != MR_SUCCESS && log_flags & LOG_RES)
377 com_err(whoami, status, " (Query failed)");
381 build_qual(fmt, argc, argv, qual)
393 for (i = 0; i < argc; i++) {
395 if (c++ == (char *)0) return(MR_ARGS);
399 *(int *)&args[i] = *(int *)argv[i]; /* sigh */
401 return(MR_INGRES_ERR);
410 sprintf(qual, fmt, args[0]);
414 sprintf(qual, fmt, args[0], args[1]);
418 sprintf(qual, fmt, args[0], args[1], args[2]);
422 sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
430 register struct validate *v;
433 register struct valobj *vo;
442 if (vo->type == V_SORT) {
443 sprintf(elem, "RET_VAR%d", vo->index + 1);
444 if (*sort) strcat(sort, ", ");
450 return ((*sort) ? sort : 0);
454 /* Build arguement vector, verify query and arguments */
456 mr_verify_query(cl, q, argc, argv_ro)
464 register struct validate *v = q->validate;
466 register int privileged = 0;
469 /* copy the arguments into a local argv that we can modify */
470 if (argc >= QMAXARGS)
472 for (i = 0; i < argc; i++) {
473 if ((len = strlen(argv_ro[i])) < ARGLEN)
474 strcpy(Argv[i], argv_ro[i]);
476 return(MR_ARG_TOO_LONG);
477 if (Argv[i][len-1] == '\\')
481 /* check initial query access */
482 status = check_query_access(q, Argv, cl);
483 if (status != MR_SUCCESS && status != MR_PERM)
485 if (status == MR_SUCCESS)
488 /* check argument count */
490 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
491 if (argc != argreq) return(MR_ARGS);
493 /* validate arguments */
494 if (v && v->valobj) {
495 status = validate_fields(q, Argv, v->valobj, v->objcnt);
496 if (status != MR_SUCCESS) return(status);
499 /* perform special query access check */
500 if (!privileged && v && v->acs_rtn) {
501 status = (*v->acs_rtn)(q, Argv, cl);
502 if (status != MR_SUCCESS && status != MR_PERM)
504 if (status == MR_SUCCESS)
508 return(privileged ? MR_SUCCESS : MR_PERM);
512 /* This routine caches info from the database. Each query acl is stored
513 * in the query structure, and whether that acl contains everybody.
516 check_query_access(q, argv, cl)
526 ## static int def_uid;
531 /* initialize default uid */
533 ## retrieve (def_uid = users.users_id) where users.login = "default"
536 /* get query access control list */
541 ## retrieve (acl_id = capacls.list_id) where capacls.tag = name
542 ## inquire_equel (rowcount = "rowcount", errorno = "errorno")
543 if (errorno != 0) return(MR_INGRES_ERR);
544 if (rowcount == 0) return(MR_PERM);
547 /* check for default access */
548 ## retrieve (exists = any(imembers.#member_id where
549 ## imembers.list_id = acl_id and
550 ## imembers.member_type = "USER" and
551 ## imembers.#member_id = def_uid))
552 q->everybody = exists;
558 if (get_client(cl, &client_type, &client_id) != MR_SUCCESS)
560 if (find_member("LIST", acl_id, client_type, client_id, 0))
567 get_client(cl, client_type, client_id)
572 if (cl->users_id > 0) {
573 *client_id = cl->users_id;
574 *client_type = "USER";
578 if (cl->client_id < 0) {
579 *client_id = -cl->users_id;
580 *client_type = "KERBEROS";
587 ##find_member(list_type, list_id, member_type, member_id)
590 ## char *member_type;
593 ## int exists, errorno;
595 if (!strcmp(strtrim(list_type), strtrim(member_type)) &&
596 list_id == member_id)
599 /* see if client is a direct member of list */
600 ## repeat retrieve (exists = any(imembers.#member_id where
601 ## imembers.#list_id = @list_id and
602 ## imembers.#member_type = @member_type and
603 ## imembers.#member_id = @member_id))
604 ## inquire_equel(errorno = "errorno")
612 do_retrieve(q, pqual, psort, action, actarg)
613 register struct query *q;
625 static char **vaddrs = (char **)NULL;
630 if ((vaddrs = (char **)malloc(sizeof(char *) * QMAXARGS)) == NULL) {
631 com_err(whoami, MR_NO_MEM, "setting up static argv");
634 for (i = 0; i < QMAXARGS; i++) {
635 if ((vaddrs[i] = malloc(QMAXARGSIZE)) == NULL) {
636 com_err(whoami, MR_NO_MEM, "setting up static argv");
645 ## range of rvar is rtable
652 ## retrieve unique (param (q->tlist, vaddrs)) where cqual
655 (*action)(q->vcnt, vaddrs, actarg);
658 ## retrieve unique (param (q->tlist, vaddrs))
661 (*action)(q->vcnt, vaddrs, actarg);
668 ## retrieve unique (param (q->tlist, vaddrs)) where cqual
670 (*action)(q->vcnt, vaddrs, actarg);
673 ## retrieve unique (param (q->tlist, vaddrs))
675 (*action)(q->vcnt, vaddrs, actarg);
680 if (mr_errcode) return(mr_errcode);
681 ## inquire_equel (rowcount = "rowcount")
682 return ((rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS);
685 do_update(q, argv, qual, action, actarg)
686 register struct query *q;
699 ## range of rvar is rtable
702 ## replace rvar (param (q->tlist, argv))
705 if (mr_errcode) return(mr_errcode);
709 do_append(q, argv, pqual, action, actarg)
710 register struct query *q;
723 ## range of rvar is rtable
727 ## append to rtable (param (q->tlist, argv)) where cqual
729 ## append to rtable (param (q->tlist, argv))
732 if (mr_errcode) return(mr_errcode);
736 do_delete(q, qual, action, actarg)
737 register struct query *q;
749 ## range of rvar is rtable
752 ## delete rvar where cqual
754 if (mr_errcode) return(mr_errcode);
760 ** set_next_object_id - set next object id in values table
762 ** Inputs: object - object name in values table and in objects
763 ** table - name of table objects are found in
765 ** - called before an APPEND operation to set the next object id to
766 ** be used for the new record to the next free value
770 set_next_object_id(object, table)
775 ## int rowcount, exists, value;
779 ## repeat retrieve (value = values.#value) where values.#name = @name
780 ## inquire_equel(rowcount = "rowcount")
784 ## retrieve (exists = any(tbl.name where tbl.name = value))
785 ## inquire_equel(rowcount = "rowcount")
790 if (value > MAX_ID_VALUE)
791 value = MIN_ID_VALUE;
792 ## retrieve (exists = any(tbl.name where tbl.name = value))
796 com_err(whoami, 0, "setting ID %s to %d", name, value);
797 ## repeat replace values (#value = @value) where values.#name = @name
802 /* Turn a kerberos name into the user's ID of the account that principal
803 * owns. Sets the kerberos ID and user ID.
806 int set_krb_mapping(name, login, ok, kid, uid)
813 ## int u_id, k_id, rowcount;
820 ## repeat retrieve (u_id = krbmap.#users_id, k_id = krbmap.#string_id)
821 ## where krbmap.string_id = strings.string_id and strings.string = @krbname
822 ## inquire_equel (rowcount = "rowcount")
823 if (ingres_errno) return(mr_errcode);
831 if (name_to_id(name, "STRINGS", &k_id) == MR_SUCCESS)
839 if (name_to_id(login, "USERS", uid) != MR_SUCCESS)
844 if (ingres_errno) return(mr_errcode);
849 /* For now this just checks the argc's. It should also see that there
850 * are no duplicate names.
853 sanity_check_queries()
856 int maxv = 0, maxa = 0;
857 #ifdef MULTIPROTOCOLS
858 extern int QueryCount1, QueryCount2;
859 extern struct query Queries1[], Queries2[];
861 extern int QueryCount2;
862 extern struct query Queries2[];
863 #endif MULTIPROTOCOLS
865 #define MAX(x,y) ((x) > (y) ? (x) : (y))
867 #ifdef MULTIPROTOCOLS
868 for (i = 0; i < QueryCount1; i++) {
869 maxv = MAX(maxv, Queries1[i].vcnt);
870 maxa = MAX(maxa, Queries1[i].argc);
872 #endif MULTIPROTOCOLS
873 for (i = 0; i < QueryCount2; i++) {
874 maxv = MAX(maxv, Queries2[i].vcnt);
875 maxa = MAX(maxa, Queries2[i].argc);
877 if (MAX(maxv, maxa) > QMAXARGS) {
878 com_err(whoami, 0, "A query has more args than QMAXARGS");