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