]> andersk Git - moira.git/blame - server/qrtn.dc
Locking the data file while it was calculating the usages on each of the
[moira.git] / server / qrtn.dc
CommitLineData
1a41acb7 1/*
2 * $Source$
3 * $Author$
4 * $Header$
b070f8a1 5 *
1a41acb7 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 *
b070f8a1 10 */
11
12#ifndef lint
048b1b94 13static char *rcsid_qrtn_dc = "$Header$";
b070f8a1 14#endif lint
15
16#include <mit-copyright.h>
17#include "query.h"
18#include "mr_server.h"
048b1b94 19EXEC SQL INCLUDE sqlca; /* SQL Communications Area */
20EXEC SQL INCLUDE sqlda; /* SQL Descriptor Area */
21#include "qrtn.h"
22
c9a214e4 23MR_SQLDA_T *SQLDA;
048b1b94 24EXEC SQL BEGIN DECLARE SECTION;
25int idummy;
26char cdummy[MR_CDUMMY_LEN];
27char stmt_buf[MR_STMTBUF_LEN];
28EXEC SQL END DECLARE SECTION;
b070f8a1 29
30char *Argv[16];
31
32int ingres_errno = 0;
33int mr_errcode = 0;
048b1b94 34EXEC SQL BEGIN DECLARE SECTION;
35int query_timeout = 30;
36EXEC SQL END DECLARE SECTION;
b070f8a1 37extern char *whoami;
38extern FILE *journal;
39
c9a214e4 40/** Maybe this should be replaced by something like tytso's sql_error */
048b1b94 41
42#define INGRES_BAD_DATE1 41206
43#define INGRES_BAD_DATE2 40207
44#define INGRES_DEADLOCK 49900
45bf7573 45
46#define INGRES_BAD_COLUMN 30110
47#define INGRES_ASGN_ERR 40204
48#define INGRES_NO_CURSOR 30120
49#define INGRES_NO_STMT 30130
50
048b1b94 51/*
52#define INGRES_BAD_INT
53#define INGRES_TIMEOUT
54#define INGRES_NO_RANGE
55 */
b070f8a1 56
c9a214e4 57
b070f8a1 58/*
59 * ingerr: (supposedly) called when Ingres indicates an error.
60 * I have not yet been able to get this to work to intercept a
61 * database open error.
62 */
63
c9a214e4 64void ingerr()
b070f8a1 65{
45bf7573 66 EXEC SQL BEGIN DECLARE SECTION;
67 char err_msg[256];
68 EXEC SQL END DECLARE SECTION;
048b1b94 69 ingres_errno = -sqlca.sqlcode;
b070f8a1 70
048b1b94 71 switch (ingres_errno) {
72/*
c9a214e4 73 * case INGRES_BAD_INT:
74 * mr_errcode = MR_INTEGER;
75 * break;
048b1b94 76 */
77 case INGRES_BAD_DATE1:
78 case INGRES_BAD_DATE2:
b070f8a1 79 mr_errcode = MR_DATE;
80 break;
81 case INGRES_DEADLOCK:
82 mr_errcode = MR_DEADLOCK;
83 com_err(whoami, 0, "INGRES deadlock detected");
84 break;
048b1b94 85/* I just don't know what the equivalent to this is, yet.
c9a214e4 86 * case INGRES_TIMEOUT:
87 * mr_errcode = MR_BUSY;
88 * com_err(whoami, 0, "timed out getting lock");
89 * break;
048b1b94 90 */
91/* This probably has no equivalent.
c9a214e4 92 * case INGRES_NO_RANGE:
93 * mr_errcode = MR_INGRES_SOFTFAIL;
94 * com_err(whoami, 0, "INGRES missing range statement");
95 * break;
048b1b94 96 */
45bf7573 97#ifdef NEVER
98 /* #ifdef-ing these out lets default: give me the INGRES text */
99 case INGRES_BAD_COLUMN:
100 mr_errcode = MR_INTERNAL;
101 com_err(whoami, 0, "Bad column name in query table");
102 break;
103 case INGRES_ASGN_ERR:
104 mr_errcode = MR_INTERNAL;
105 com_err(whoami, 0, "Error in SQL assignment statement");
106 break;
107 case INGRES_NO_CURSOR:
108 mr_errcode = MR_INTERNAL;
109 com_err(whoami, 0, "Cursor not opened");
110 break;
111 case INGRES_NO_STMT:
112 mr_errcode = MR_INTERNAL;
113 com_err(whoami, 0, "Statement not declared");
114 break;
115#endif
b070f8a1 116 default:
048b1b94 117 /** Add the INGRES error_text to the alert message ??? **/
b070f8a1 118 mr_errcode = MR_INGRES_ERR;
45bf7573 119 com_err(whoami, MR_INGRES_ERR, " code %d\n", ingres_errno);
120 EXEC SQL INQUIRE_SQL(:err_msg = errortext);
121 com_err(whoami, 0, "SQL error text = %s", err_msg);
c9a214e4 122 critical_alert("MOIRA", "Moira server encountered INGRES ERROR %d", ingres_errno);
b070f8a1 123 }
b070f8a1 124}
125
45bf7573 126/* This is declarative, not executed. Applies from here on, in this file. */
048b1b94 127EXEC SQL WHENEVER SQLERROR CALL ingerr;
128
b070f8a1 129int mr_open_database()
130{
131 register int i;
132 char *malloc();
c9a214e4 133 MR_SQLDA_T *mr_alloc_SQLDA();
b070f8a1 134 static first_open = 1;
135
136 if (first_open) {
137 first_open = 0;
138
139 /* initialize local argv */
140 for (i = 0; i < 16; i++)
141 Argv[i] = malloc(ARGLEN);
142
c9a214e4 143 SQLDA = mr_alloc_SQLDA();
144
b070f8a1 145 incremental_init();
146 flush_cache();
147 }
148
149 ingres_errno = 0;
150 mr_errcode = 0;
151
152 /* open the database */
048b1b94 153#ifsql INGRES
154 EXEC SQL CONNECT moira;
155 EXEC SQL set lockmode session where level = table, timeout = :query_timeout;
156 EXEC SQL set lockmode on capacls where readlock = shared;
157 EXEC SQL set lockmode on alias where readlock = shared;
158#endsql
159#ifsql INFORMIX
160 EXEC SQL DATABASE moira
161#endsql
b070f8a1 162 return ingres_errno;
163}
164
165int mr_close_database()
166{
167 flush_cache();
048b1b94 168#ifsql INGRES
169 EXEC SQL DISCONNECT;
170#endsql
b070f8a1 171}
172
173mr_check_access(cl, name, argc, argv_ro)
174 client *cl;
175 char *name;
176 int argc;
177 char *argv_ro[];
178{
179 struct query *q;
180 struct query *get_query_by_name();
181
182 ingres_errno = 0;
183 mr_errcode = 0;
184
185 q = get_query_by_name(name, cl->args->mr_version_no);
186 if (q == (struct query *)0)
187 return(MR_NO_HANDLE);
188
048b1b94 189 return(mr_verify_query(cl, q, argc, argv_ro));
b070f8a1 190}
191
192mr_process_query(cl, name, argc, argv_ro, action, actarg)
193 client *cl;
194 char *name;
195 int argc;
196 char *argv_ro[];
197 int (*action)();
198 char *actarg;
199{
200 register struct query *q;
201 register int status;
202 register struct validate *v;
203 char qual[256];
204 char sort[32];
205 char *pqual;
206 char *psort;
048b1b94 207 EXEC SQL BEGIN DECLARE SECTION;
208 char *table_name;
209 EXEC SQL END DECLARE SECTION;
b070f8a1 210 struct save_queue *sq;
211 struct query *get_query_by_name();
212 int sq_save_args();
213 struct save_queue *sq_create();
214 char *build_sort();
215
216 ingres_errno = 0;
217 mr_errcode = 0;
218
219 /* list queries command */
220 if (!strcmp(name, "_list_queries")) {
221 list_queries(cl->args->mr_version_no, action, actarg);
222 return(MR_SUCCESS);
223 }
224
225 /* help query command */
226 if (!strcmp(name, "_help")) {
227 if (argc < 1)
228 return(MR_ARGS);
229 q = get_query_by_name(argv_ro[0], cl->args->mr_version_no);
230 if (q == (struct query *)0) return(MR_NO_HANDLE);
231 help_query(q, action, actarg);
232 return(MR_SUCCESS);
233 }
234
235 /* get query structure, return error if named query does not exist */
236 q = get_query_by_name(name, cl->args->mr_version_no);
237 if (q == (struct query *)0) return(MR_NO_HANDLE);
238 v = q->validate;
239
240 /* setup argument vector, verify access and arguments */
241 if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
242 goto out;
243
244 /* perform any special query pre-processing */
245 if (v && v->pre_rtn) {
246 status = (*v->pre_rtn)(q, Argv, cl, 0);
247 if (status != MR_SUCCESS)
248 goto out;
249 }
250
251 switch (q->type) {
252 case RETRIEVE:
253 /* for queries that do not permit wildcarding, check if row
254 uniquely exists */
255 if (v && v->field) {
048b1b94 256 status = validate_row(q, Argv, v);
b070f8a1 257 if (status != MR_EXISTS) break;
258 }
259
260 /* build "where" clause if needed */
261 if (q->qual) {
048b1b94 262 build_qual(q->qual, q->argc, Argv, qual);
b070f8a1 263 pqual = qual;
264 } else {
265 pqual = 0;
266 }
267
268 /* build "sort" clause if needed */
269 if (v && v->valobj) {
270 psort = build_sort(v, sort);
271 } else {
272 psort = 0;
273 }
274
275 /* if there is a followup routine, then we must save the results */
276 /* of the first query for use by the followup routine */
277 /* if q->rvar = NULL, perform post_rtn only */
278 if (q->rvar) {
279 if (v && v->post_rtn) {
280 sq = sq_create();
281 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
282 if (status != MR_SUCCESS) {
283 sq_destroy(sq);
284 break;
285 }
286 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
287 } else {
288 /* normal retrieve */
289 status = do_retrieve(q, pqual, psort, action, actarg);
290 }
291 if (status != MR_SUCCESS) break;
292 } else {
293 status = (*v->post_rtn)(q, Argv, cl, action, actarg);
294 }
295
296 break;
297
298 case UPDATE:
299 /* see if row already exists */
300 if (v->field) {
301 status = validate_row(q, Argv, v);
302 if (status != MR_EXISTS) break;
303 }
304
305 /* build "where" clause and perform update */
306 /* if q->rvar = NULL, perform post_rtn only */
307 if (q->rvar) {
308 build_qual(q->qual, q->argc, Argv, qual);
309 incremental_before(q->rtable, qual, argv_ro);
310 status = do_update(q, &Argv[q->argc], qual, action, actarg);
311 incremental_after(q->rtable, qual, argv_ro);
312 if (status != MR_SUCCESS) break;
313 flush_name(argv_ro[0], q->rtable);
048b1b94 314 table_name = q->rtable;
b070f8a1 315 if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif")) {
048b1b94 316 EXEC SQL UPDATE tblstats
317 SET updates = updates + 1, modtime = 'now'
318 WHERE table_name = :table_name;
b070f8a1 319 }
320 }
321
322 /* execute followup routine (if any) */
323 if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
324
325 break;
326
327 case APPEND:
328 /* see if row already exists */
329 if (v->field) {
330 status = validate_row(q, Argv, v);
331 if (status != MR_NO_MATCH) break;
332 }
333
45bf7573 334#ifdef NEVER
335 /* This is now done by a valobj, which also fetches the id value */
336
b070f8a1 337 /* increment id number if necessary */
338 if (v->object_id) {
1a41acb7 339 status = set_next_object_id(v->object_id, q->rtable, 0);
b070f8a1 340 if (status != MR_SUCCESS) break;
341 }
45bf7573 342#endif
b070f8a1 343
344 /* build "where" clause if needed */
345 if (q->qual) {
346 build_qual(q->qual, q->argc, Argv, qual);
347 pqual = qual;
348 } else {
349 pqual = 0;
350 }
351
352 /* perform the append */
353 /* if q->rvar = NULL, perform post_rtn only */
354 if (q->rvar) {
355 incremental_clear_before();
356 status = do_append(q, &Argv[q->argc], pqual, action, actarg);
357 if (status != MR_SUCCESS) break;
358 if (v && v->object_id) {
45bf7573 359 sprintf(qual, "%s.%s = %s",q->rtable, v->object_id,
360 Argv[q->argc+q->vcnt]);
b070f8a1 361 incremental_after(q->rtable, qual, argv_ro);
362 } else
363 incremental_after(q->rtable, pqual, argv_ro);
364
048b1b94 365 table_name = q->rtable;
366 EXEC SQL UPDATE tblstats
367 SET appends = appends + 1, modtime = 'now'
368 WHERE table_name = :table_name;
b070f8a1 369 }
370
371 /* execute followup routine */
372 if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
373 break;
374
375 case DELETE:
376 /* see if row already exists */
377 if (v->field) {
378 status = validate_row(q, Argv, v);
379 if (status != MR_EXISTS) break;
380 }
381
382 /* build "where" clause and perform delete */
383 /* if q->rvar = NULL, perform post_rtn only */
384 if (q->rvar) {
385 build_qual(q->qual, q->argc, Argv, qual);
048b1b94 386 table_name = q->rtable;
387 incremental_before(q->rtable, qual, argv_ro);
b070f8a1 388 status = do_delete(q, qual, action, actarg);
389 incremental_clear_after();
390 if (status != MR_SUCCESS) break;
391 flush_name(argv_ro[0], q->rtable);
048b1b94 392 EXEC SQL UPDATE tblstats
393 SET deletes = deletes + 1, modtime = 'now'
394 WHERE table_name = :table_name;
b070f8a1 395 }
396
397 /* execute followup routine */
398 if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
399 break;
400
401 }
402
403out:
404 if (status == MR_SUCCESS && ingres_errno != 0) {
405 com_err(whoami, MR_INTERNAL, "Server didn't notice INGRES ERROR %d",
406 ingres_errno);
407 status = mr_errcode;
408 }
409
048b1b94 410 if (q->type == RETRIEVE) {
048b1b94 411 EXEC SQL COMMIT WORK;
048b1b94 412 } else {
b070f8a1 413 if (status == MR_SUCCESS) {
048b1b94 414 EXEC SQL COMMIT WORK;
b070f8a1 415 if (journal) {
416 char buf[1024], *bp;
417 int i;
418 extern time_t now;
419
420 fprintf(journal, "%% %s %s %s",
421 cl->clname, cl->entity, ctime(&now));
422 fprintf(journal, "%s[%d] ", q->name, cl->args->mr_version_no);
423 for (i = 0; i < argc; i++) {
424 if (i != 0) {
425 putc(' ', journal);
426 }
427 requote(buf, argv_ro[i], sizeof(buf));
428 fputs(buf, journal);
429 }
430 putc('\n', journal);
431 fflush(journal);
432 }
433 incremental_update();
434 } else {
1a41acb7 435 cache_abort();
b070f8a1 436 if (ingres_errno != INGRES_DEADLOCK) {
048b1b94 437 EXEC SQL ROLLBACK WORK;
b070f8a1 438 }
439 incremental_flush();
440 }
441 }
1a41acb7 442 cache_commit(); /* commit following abort is safe */
b070f8a1 443
444 if (status != MR_SUCCESS && log_flags & LOG_RES)
445 com_err(whoami, status, " (Query failed)");
446 return(status);
447}
448
449build_qual(fmt, argc, argv, qual)
450 char *fmt;
451 int argc;
452 char *argv[];
453 char *qual;
454{
455 register char *c;
456 register int i;
457 char *args[4];
458 char *index();
459
460 c = fmt;
461 for (i = 0; i < argc; i++) {
462 c = index(c, '%');
463 if (c++ == (char *)0) return(MR_ARGS);
464 if (*c == 's')
465 args[i] = argv[i];
466 else if (*c == 'd')
467 *(int *)&args[i] = *(int *)argv[i]; /* sigh */
468 else
469 return(MR_INGRES_ERR);
470 }
1a41acb7 471 if (c = index(c, '%')) {
472 args[i] = args[i - 1];
473 }
b070f8a1 474
475 switch (argc) {
476 case 0:
477 strcpy(qual, fmt);
478 break;
479
480 case 1:
481 sprintf(qual, fmt, args[0]);
482 break;
483
484 case 2:
485 sprintf(qual, fmt, args[0], args[1]);
486 break;
487
488 case 3:
489 sprintf(qual, fmt, args[0], args[1], args[2]);
490 break;
491
492 case 4:
493 sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
494 break;
1a41acb7 495
496 default:
497 com_err(whoami, MR_INTERNAL,
498 "Internal arg count error processing query");
499 return(MR_INTERNAL);
b070f8a1 500 }
501 return(MR_SUCCESS);
502}
503
504char *
505build_sort(v, sort)
506 register struct validate *v;
507 char *sort;
508{
509 register struct valobj *vo;
510 register int n;
511 char elem[16];
512
513 n = v->objcnt;
514 vo = v->valobj;
515 *sort = 0;
516
517 while (--n >= 0) {
518 if (vo->type == V_SORT) {
048b1b94 519 sprintf(elem, "%d", vo->index + 1); /* Result column number */
b070f8a1 520 if (*sort) strcat(sort, ", ");
521 strcat(sort, elem);
522 }
523 vo++;
524 }
525
526 return ((*sort) ? sort : 0);
527}
528
529
530/* Build arguement vector, verify query and arguments */
531
532mr_verify_query(cl, q, argc, argv_ro)
533 client *cl;
534 struct query *q;
535 int argc;
536 char *argv_ro[];
537{
538 register int argreq;
539 register int status;
540 register struct validate *v = q->validate;
541 register int i;
542 register int privileged = 0;
543 int len;
544
545 /* copy the arguments into a local argv that we can modify */
546 if (argc >= QMAXARGS)
547 return(MR_ARGS);
548 for (i = 0; i < argc; i++) {
549 if ((len = strlen(argv_ro[i])) < ARGLEN)
550 strcpy(Argv[i], argv_ro[i]);
551 else
552 return(MR_ARG_TOO_LONG);
553 if (Argv[i][len-1] == '\\')
554 return(MR_BAD_CHAR);
555 }
556
557 /* check initial query access */
558 status = check_query_access(q, Argv, cl);
559 if (status != MR_SUCCESS && status != MR_PERM)
560 return(status);
561 if (status == MR_SUCCESS)
562 privileged++;
563
564 /* check argument count */
565 argreq = q->argc;
566 if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
567 if (argc != argreq) return(MR_ARGS);
568
569 /* validate arguments */
570 if (v && v->valobj) {
571 status = validate_fields(q, Argv, v->valobj, v->objcnt);
572 if (status != MR_SUCCESS) return(status);
573 }
574
575 /* perform special query access check */
576 if (!privileged && v && v->acs_rtn) {
577 status = (*v->acs_rtn)(q, Argv, cl);
578 if (status != MR_SUCCESS && status != MR_PERM)
579 return(status);
580 if (status == MR_SUCCESS)
581 privileged++;
582 }
583
584 return(privileged ? MR_SUCCESS : MR_PERM);
585}
586
587
588/* This routine caches info from the database. Each query acl is stored
589 * in the query structure, and whether that acl contains everybody.
590 */
591
592check_query_access(q, argv, cl)
593 struct query *q;
594 char *argv[];
595 client *cl;
048b1b94 596{
597 EXEC SQL BEGIN DECLARE SECTION;
598 char *name;
599 int acl_id;
600 int rowcount;
601 int errorno;
602 static int def_uid;
603 EXEC SQL END DECLARE SECTION;
b070f8a1 604 int status;
605 int client_id;
606 char *client_type;
607
608 /* initialize default uid */
609 if (def_uid == 0) {
048b1b94 610 EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login='default';
b070f8a1 611 }
612
613 /* get query access control list */
614 if (q->acl != 0)
615 acl_id = q->acl;
616 else {
617 name = q->shortname;
048b1b94 618 EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
619 if (sqlca.sqlcode < 0) return(MR_INGRES_ERR);
620 if (sqlca.sqlcode == 100) return(MR_PERM);
b070f8a1 621 q->acl = acl_id;
622
623 /* check for default access */
048b1b94 624 EXEC SQL SELECT member_id INTO :acl_id FROM imembers
625 WHERE list_id = :acl_id AND member_type = 'USER'
626 AND member_id = :def_uid;
627 if (sqlca.sqlerrd[2] == 0)
628 q->everybody = 0;
629 else
630 q->everybody = 1;
b070f8a1 631 }
632
633 if (q->everybody)
634 return(MR_SUCCESS);
635
636 if (get_client(cl, &client_type, &client_id) != MR_SUCCESS)
637 return(MR_PERM);
638 if (find_member("LIST", acl_id, client_type, client_id, 0))
639 return(MR_SUCCESS);
640 else
641 return(MR_PERM);
048b1b94 642}
b070f8a1 643
644
645get_client(cl, client_type, client_id)
646 client *cl;
647 char **client_type;
648 int *client_id;
649{
650 if (cl->users_id > 0) {
651 *client_id = cl->users_id;
652 *client_type = "USER";
653 return(MR_SUCCESS);
654 }
655
656 if (cl->client_id < 0) {
657 *client_id = -cl->users_id;
658 *client_type = "KERBEROS";
659 return(MR_SUCCESS);
660 }
661
662 return(MR_PERM);
663}
664
048b1b94 665find_member(list_type, list_id, member_type, member_id)
1a41acb7 666 char *list_type;
048b1b94 667 EXEC SQL BEGIN DECLARE SECTION;
668 int list_id;
669 char *member_type;
670 int member_id;
671 EXEC SQL END DECLARE SECTION;
672{
673 EXEC SQL BEGIN DECLARE SECTION;
674 int flag, errorno;
675 EXEC SQL END DECLARE SECTION;
b070f8a1 676
677 if (!strcmp(strtrim(list_type), strtrim(member_type)) &&
678 list_id == member_id)
679 return(1);
680
681 /* see if client is a direct member of list */
048b1b94 682 flag = 0;
683 EXEC SQL SELECT member_id INTO :flag FROM imembers
684 WHERE list_id = :list_id AND member_type = :member_type
685 AND member_id = :member_id;
686 if(flag!=0) flag=1; /** Not strictly necessary */
687 if (sqlca.sqlcode == 0)
688 return(flag);
689 return(0);
690}
b070f8a1 691
692
048b1b94 693do_retrieve(q, pqual, psort, action, actarg)
b070f8a1 694 register struct query *q;
048b1b94 695EXEC SQL BEGIN DECLARE SECTION;
b070f8a1 696 char *pqual;
697 char *psort;
048b1b94 698EXEC SQL END DECLARE SECTION;
b070f8a1 699 int (*action)();
700 char *actarg;
048b1b94 701{
b070f8a1 702 static char **vaddrs = (char **)NULL;
c9a214e4 703 int j, rowcount;
b070f8a1 704
705 if (!vaddrs) {
706 register int i;
707
708 if ((vaddrs = (char **)malloc(sizeof(char *) * QMAXARGS)) == NULL) {
709 com_err(whoami, MR_NO_MEM, "setting up static argv");
710 exit(1);
711 }
45bf7573 712 for (i = 0; i < QMAXARGS; i++) {
c9a214e4 713 vaddrs[i]=SQLDA->sqlvar[i].sqldata;
b070f8a1 714 }
715 }
716
c9a214e4 717 build_sql_stmt(stmt_buf,"SELECT",q->tlist,vaddrs,pqual);
048b1b94 718 if(psort) { strcat(stmt_buf," ORDER BY "); strcat(stmt_buf,psort); }
c9a214e4 719 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
45bf7573 720 if(ingres_errno)
721 return(mr_errcode);
c9a214e4 722 if((mr_errcode=mr_check_SQLDA(SQLDA)) != MR_SUCCESS)
723 return(mr_errcode);
048b1b94 724 EXEC SQL DECLARE csr001 CURSOR FOR stmt;
725 EXEC SQL OPEN csr001;
c9a214e4 726 rowcount = 0;
048b1b94 727 while(1) {
728 EXEC SQL FETCH csr001 USING DESCRIPTOR :SQLDA;
729 if(sqlca.sqlcode != 0) break;
730 (*action)(q->vcnt, vaddrs, actarg);
c9a214e4 731 rowcount++;
b070f8a1 732 }
048b1b94 733 EXEC SQL CLOSE csr001;
b070f8a1 734
735 if (mr_errcode) return(mr_errcode);
c9a214e4 736 return ((rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS);
048b1b94 737}
738
739build_sql_stmt(result_buf,cmd,targetlist,argv,qual)
740 char *result_buf;
741 char *cmd;
742 char *targetlist;
743 char *argv[];
c9a214e4 744 char *qual;
048b1b94 745{
746 char fmt_buf[MR_STMTBUF_LEN];
747 char tmp_buf[16];
45bf7573 748 register char *res=result_buf, *tmp=tmp_buf, *fmt=fmt_buf;
749 register int state;
048b1b94 750
751 sprintf(fmt_buf,"%s %s",cmd,targetlist);
752 if(qual) { strcat(fmt_buf," WHERE "); strcat(fmt_buf,qual); }
753
c9a214e4 754 for(state=0;*fmt != '\0';fmt++) {
048b1b94 755 switch(state) {
756 case 0:
757 if(*fmt=='%') { /* formatting -> tmp */
c9a214e4 758 *tmp++ = *fmt;
048b1b94 759 state=1;
45bf7573 760 } else *res++ = *fmt; /* text -> res */
048b1b94 761 break;
762 case 1:
763 if((*fmt=='%') && (tmp==tmp_buf+1)) { /* %% -> % */
c9a214e4 764 *res++ = *fmt;
048b1b94 765 tmp=tmp_buf;
766 state=0;
767 } else if(isalpha(*fmt) && (*fmt!='h') && (*fmt!='l')) { /* end of formatting */
c9a214e4 768 *tmp++ = *fmt;
048b1b94 769 *tmp='\0';
770 tmp=tmp_buf;
771 sprintf(res,tmp_buf,*argv++); /* print to result buffer */
45bf7573 772 while(*++res) ;
048b1b94 773 state=0;
c9a214e4 774 } else *tmp++ = *fmt; /* keep copying the formatting to tmp */
048b1b94 775 break;
776 }
777 }
778 *res='\0';
779}
b070f8a1 780
781do_update(q, argv, qual, action, actarg)
782 register struct query *q;
783 char *argv[];
784 char *qual;
785 int (*action)();
786 char *actarg;
048b1b94 787{
788 build_sql_stmt(stmt_buf,"UPDATE",q->tlist,argv,qual);
c9a214e4 789 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
b070f8a1 790 if (mr_errcode) return(mr_errcode);
791 return(MR_SUCCESS);
048b1b94 792}
b070f8a1 793
794do_append(q, argv, pqual, action, actarg)
795 register struct query *q;
796 char *argv[];
797 char *pqual;
798 int (*action)();
799 char *actarg;
048b1b94 800{
801 build_sql_stmt(stmt_buf,"INSERT",q->tlist,argv,pqual);
c9a214e4 802 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
b070f8a1 803 if (mr_errcode) return(mr_errcode);
804 return(MR_SUCCESS);
048b1b94 805}
b070f8a1 806
807do_delete(q, qual, action, actarg)
808 register struct query *q;
809 char *qual;
810 int (*action)();
811 char *actarg;
048b1b94 812{
813 sprintf(stmt_buf,"DELETE FROM %s WHERE %s",q->rtable,qual);
814 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
b070f8a1 815 if (mr_errcode) return(mr_errcode);
816 return(MR_SUCCESS);
048b1b94 817}
b070f8a1 818
819
820/**
821 ** set_next_object_id - set next object id in values table
822 **
823 ** Inputs: object - object name in values table and in objects
824 ** table - name of table objects are found in
1a41acb7 825 ** limit - should the ID be range limited
b070f8a1 826 **
827 ** - called before an APPEND operation to set the next object id to
828 ** be used for the new record to the next free value
829 **
830 **/
831
048b1b94 832set_next_object_id(object, table_name, limit)
833 EXEC SQL BEGIN DECLARE SECTION;
1a41acb7 834 char *object;
048b1b94 835 char *table_name;
1a41acb7 836 int limit;
048b1b94 837 EXEC SQL END DECLARE SECTION;
838{
839 EXEC SQL BEGIN DECLARE SECTION;
c9a214e4 840 int value;
048b1b94 841 EXEC SQL END DECLARE SECTION;
45bf7573 842 int starting_value;
843
048b1b94 844 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :object;
845 if (sqlca.sqlerrd[2] != 1)
1a41acb7 846 return(MR_NO_ID);
847
45bf7573 848 starting_value=value;
c9a214e4 849 while (1) {
45bf7573 850 if (limit && value > MAX_ID_VALUE)
851 value = MIN_ID_VALUE;
852
853 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s=%d",object,table_name,object,value);
854 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
855 EXEC SQL DECLARE csr002 CURSOR FOR stmt;
c9a214e4 856 EXEC SQL OPEN csr002;
45bf7573 857 EXEC SQL FETCH csr002 USING DESCRIPTOR :SQLDA;
858 if (sqlca.sqlcode < 0) return(mr_errcode);
859 if (sqlca.sqlcode == 100) break;
860
c9a214e4 861 EXEC SQL CLOSE csr002;
45bf7573 862 value++;
863 if (limit && value == starting_value) {
864 com_err(whoami,0,"All id values have been used");
865 return(MR_NO_ID);
866 }
b070f8a1 867 }
c9a214e4 868 EXEC SQL CLOSE csr002;
b070f8a1 869
870 if (LOG_RES)
c9a214e4 871 com_err(whoami, 0, "setting ID %s to %d", object, value);
048b1b94 872 EXEC SQL UPDATE numvalues SET value = :value WHERE name = :object;
b070f8a1 873 return(MR_SUCCESS);
048b1b94 874}
b070f8a1 875
876
877/* Turn a kerberos name into the user's ID of the account that principal
878 * owns. Sets the kerberos ID and user ID.
879 */
880
881int set_krb_mapping(name, login, ok, kid, uid)
882char *name;
883char *login;
884int ok;
885int *kid;
886int *uid;
048b1b94 887{
888 EXEC SQL BEGIN DECLARE SECTION;
889 int u_id, k_id;
890 char *krbname;
891 EXEC SQL END DECLARE SECTION;
b070f8a1 892
893 krbname = name;
894 *kid = 0;
895 *uid = 0;
896
048b1b94 897 EXEC SQL SELECT k.users_id, k.string_id INTO :u_id, :k_id
898 FROM krbmap k, strings s
899 WHERE k.string_id = s.string_id AND s.string = :krbname;
900
b070f8a1 901 if (ingres_errno) return(mr_errcode);
902
048b1b94 903 if (sqlca.sqlerrd[2] == 1) { /* rowcount */
b070f8a1 904 *kid = -k_id;
905 *uid = u_id;
906 return(MR_SUCCESS);
907 }
908
909 if (name_to_id(name, "STRINGS", &k_id) == MR_SUCCESS)
910 *kid = -k_id;
911
048b1b94 912 if (!ok) {
b070f8a1 913 *uid = *kid;
914 return(MR_SUCCESS);
915 }
916
917 if (name_to_id(login, "USERS", uid) != MR_SUCCESS)
918 *uid = 0;
919
920 if (*kid == 0)
921 *kid = *uid;
922 if (ingres_errno) return(mr_errcode);
923 return(MR_SUCCESS);
048b1b94 924}
b070f8a1 925
926
927/* For now this just checks the argc's. It should also see that there
928 * are no duplicate names.
929 */
930
931sanity_check_queries()
932{
933 register int i;
934 int maxv = 0, maxa = 0;
935#ifdef MULTIPROTOCOLS
936 extern int QueryCount1, QueryCount2;
937 extern struct query Queries1[], Queries2[];
938#else
939 extern int QueryCount2;
940 extern struct query Queries2[];
941#endif MULTIPROTOCOLS
942
943#define MAX(x,y) ((x) > (y) ? (x) : (y))
944
945#ifdef MULTIPROTOCOLS
946 for (i = 0; i < QueryCount1; i++) {
947 maxv = MAX(maxv, Queries1[i].vcnt);
948 maxa = MAX(maxa, Queries1[i].argc);
949 }
950#endif MULTIPROTOCOLS
951 for (i = 0; i < QueryCount2; i++) {
952 maxv = MAX(maxv, Queries2[i].vcnt);
953 maxa = MAX(maxa, Queries2[i].argc);
954 }
955 if (MAX(maxv, maxa) > QMAXARGS) {
956 com_err(whoami, 0, "A query has more args than QMAXARGS");
957 exit(1);
958 }
959}
048b1b94 960
961/* eof:qrtn.dc */
This page took 0.21021 seconds and 5 git commands to generate.