]> andersk Git - moira.git/blame - server/qrtn.pc
add tag support
[moira.git] / server / qrtn.pc
CommitLineData
7ac48069 1/* $Id$
2 *
3 * Query-processing routines
b070f8a1 4 *
7ac48069 5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
5eaef520 8 *
b070f8a1 9 */
10
b070f8a1 11#include <mit-copyright.h>
b070f8a1 12#include "mr_server.h"
7ac48069 13#include "qrtn.h"
03c05291 14#include "query.h"
7ac48069 15
85330553 16#include <stdio.h>
7ac48069 17#include <stdlib.h>
18#include <string.h>
19
048b1b94 20EXEC SQL INCLUDE sqlca; /* SQL Communications Area */
21EXEC SQL INCLUDE sqlda; /* SQL Descriptor Area */
7ac48069 22
23RCSID("$Header$");
048b1b94 24
03c05291 25SQLDA *mr_sqlda;
5eaef520 26EXEC SQL BEGIN DECLARE SECTION;
1741dca0 27int mr_sig_length;
048b1b94 28char stmt_buf[MR_STMTBUF_LEN];
ce8337ff 29int proxy_acl;
5eaef520 30EXEC SQL END DECLARE SECTION;
b070f8a1 31
30cf9ed3 32char *Argv[QMAXARGS];
03c05291 33extern char *table_name[];
34extern char *sqlbuffer[QMAXARGS];
b070f8a1 35
03c05291 36int dbms_errno = 0;
b070f8a1 37int mr_errcode = 0;
5eaef520 38EXEC SQL BEGIN DECLARE SECTION;
048b1b94 39int query_timeout = 30;
923a939b 40char *database = "moira";
048b1b94 41EXEC SQL END DECLARE SECTION;
b070f8a1 42extern char *whoami;
43extern FILE *journal;
c44ddfa7 44extern int QueryCount, max_version;
45extern struct query Queries[];
b070f8a1 46
b131e4a0 47/* Put this in a variable so that we can patch it if necessary */
48int max_row_count = 4096;
49
03c05291 50int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
29028043 51int do_retrieve(struct query *q, char *pqual,
7ac48069 52 int (*action)(int, char *[], void *), void *actarg);
03c05291 53int do_update(struct query *q, char *argv[], char *qual,
7ac48069 54 int (*action)(int, char *[], void *), void *actarg);
03c05291 55int do_append(struct query *q, char *argv[], char *pqual,
7ac48069 56 int (*action)(int, char *[], void *), void *actarg);
03c05291 57int do_delete(struct query *q, char *qual,
7ac48069 58 int (*action)(int, char *[], void *), void *actarg);
03c05291 59void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
60 char *argv[], char *qual);
03c05291 61
7ac48069 62SQLDA *mr_alloc_sqlda(void);
63void sqlglm(char *, int *, int *);
45bf7573 64
048b1b94 65/*
03c05291 66 * dbmserr: Called when the DBMS indicates an error.
b070f8a1 67 */
68
03c05291 69void dbmserr(void)
b070f8a1 70{
5eaef520 71 EXEC SQL BEGIN DECLARE SECTION;
72 char err_msg[256];
73 EXEC SQL END DECLARE SECTION;
74 int bufsize = 256, msglength = 0;
75
76 dbms_errno = -sqlca.sqlcode;
77 mr_errcode = MR_DBMS_ERR;
78 com_err(whoami, MR_DBMS_ERR, " code %d\n", dbms_errno);
79 sqlglm(err_msg, &bufsize, &msglength);
80 err_msg[msglength] = 0;
81 com_err(whoami, 0, "SQL error text = %s", err_msg);
82 critical_alert("MOIRA", "Moira server encountered DBMS ERROR %d\n%s",
83 dbms_errno, err_msg);
b070f8a1 84}
85
45bf7573 86/* This is declarative, not executed. Applies from here on, in this file. */
03c05291 87EXEC SQL WHENEVER SQLERROR DO dbmserr();
048b1b94 88
03c05291 89int mr_open_database(void)
b070f8a1 90{
44d12d58 91 int i;
c44ddfa7 92 static int first_open = 1;
b070f8a1 93
5eaef520 94 if (first_open)
95 {
96 first_open = 0;
b070f8a1 97
5eaef520 98 /* initialize local argv */
99 for (i = 0; i < 16; i++)
e688520a 100 Argv[i] = xmalloc(MAX_FIELD_WIDTH);
b070f8a1 101
5eaef520 102 mr_sqlda = mr_alloc_sqlda();
c9a214e4 103
5eaef520 104 incremental_init();
105 flush_cache();
b070f8a1 106 }
b070f8a1 107
5eaef520 108 dbms_errno = 0;
109 mr_errcode = 0;
03c05291 110
5eaef520 111 /* open the database */
112 EXEC SQL CONNECT :database IDENTIFIED BY :database;
1741dca0 113
5eaef520 114 if (dbms_errno)
115 return mr_errcode;
1741dca0 116
5eaef520 117 EXEC SQL SELECT data_length INTO :mr_sig_length FROM user_tab_columns
118 WHERE table_name = 'USERS' and column_name = 'SIGNATURE';
ce8337ff 119 if (dbms_errno)
120 return mr_errcode;
121 EXEC SQL SELECT list_id INTO :proxy_acl FROM capacls
122 WHERE capability = 'proxy';
5eaef520 123 if (dbms_errno)
124 return mr_errcode;
125
126 return MR_SUCCESS;
b070f8a1 127}
128
03c05291 129void mr_close_database(void)
b070f8a1 130{
5eaef520 131 flush_cache();
132 EXEC SQL COMMIT RELEASE;
b070f8a1 133}
134
5eaef520 135int mr_check_access(client *cl, char *name, int argc, char *argv_ro[])
b070f8a1 136{
5eaef520 137 struct query *q;
b070f8a1 138
5eaef520 139 dbms_errno = 0;
140 mr_errcode = 0;
b070f8a1 141
c44ddfa7 142 q = get_query_by_name(name, cl->version);
5eaef520 143 if (!q)
144 return MR_NO_HANDLE;
b070f8a1 145
5eaef520 146 return mr_verify_query(cl, q, argc, argv_ro);
b070f8a1 147}
148
5eaef520 149int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
7ac48069 150 int (*action)(int, char *[], void *), void *actarg)
b070f8a1 151{
44d12d58 152 struct query *q;
153 int status;
154 struct validate *v;
263a36d4 155 char *qual = NULL;
5eaef520 156 EXEC SQL BEGIN DECLARE SECTION;
157 char *table;
158 EXEC SQL END DECLARE SECTION;
159 struct save_queue *sq;
160
161 dbms_errno = 0;
162 mr_errcode = 0;
b070f8a1 163
5eaef520 164 /* list queries command */
165 if (!strcmp(name, "_list_queries"))
166 {
85330553 167 list_queries(action, actarg);
5eaef520 168 return MR_SUCCESS;
b070f8a1 169 }
170
5eaef520 171 /* help query command */
172 if (!strcmp(name, "_help"))
173 {
174 if (argc < 1)
175 return MR_ARGS;
c44ddfa7 176 q = get_query_by_name(argv_ro[0], cl->version);
5eaef520 177 if (!q)
178 return MR_NO_HANDLE;
179 help_query(q, action, actarg);
180 return MR_SUCCESS;
181 }
b070f8a1 182
5eaef520 183 /* get query structure, return error if named query does not exist */
c44ddfa7 184 q = get_query_by_name(name, cl->version);
5eaef520 185 if (!q)
186 return MR_NO_HANDLE;
187 v = q->validate;
188
189 /* setup argument vector, verify access and arguments */
190 if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
191 goto out;
192
193 /* perform any special query pre-processing */
194 if (v && v->pre_rtn)
195 {
7ac48069 196 status = (*v->pre_rtn)(q, Argv, cl);
5eaef520 197 if (status != MR_SUCCESS)
b070f8a1 198 goto out;
b070f8a1 199 }
200
5eaef520 201 switch (q->type)
202 {
b070f8a1 203 case RETRIEVE:
5eaef520 204 /* for queries that do not permit wildcarding, check if row
205 uniquely exists */
206 if (v && v->field)
207 {
208 status = validate_row(q, Argv, v);
209 if (status != MR_EXISTS)
210 break;
b070f8a1 211 }
212
5eaef520 213 /* build "where" clause if needed */
214 if (q->qual)
263a36d4 215 qual = build_qual(q->qual, q->argc, Argv);
5eaef520 216
5eaef520 217 /* if there is a followup routine, then we must save the results */
218 /* of the first query for use by the followup routine */
219 /* if q->rvar = NULL, perform post_rtn only */
220 if (q->rvar)
221 {
222 if (v && v->post_rtn)
223 {
224 sq = sq_create();
263a36d4 225 status = do_retrieve(q, qual, sq_save_args, sq);
5eaef520 226 if (status != MR_SUCCESS)
227 {
b131e4a0 228 char **argv;
229 int i;
230
231 while (sq_get_data(sq, &argv))
232 {
233 for (i = 0; i < q->vcnt; i++)
234 free(argv[i]);
235 free(argv);
236 }
5eaef520 237 sq_destroy(sq);
238 break;
b070f8a1 239 }
5eaef520 240 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
241 }
242 else
243 {
244 /* normal retrieve */
263a36d4 245 status = do_retrieve(q, qual, action, actarg);
b070f8a1 246 }
5eaef520 247 if (status != MR_SUCCESS)
248 break;
b070f8a1 249 }
5eaef520 250 else
251 status = (*v->post_rtn)(q, Argv, cl, action, actarg);
b070f8a1 252
5eaef520 253 break;
b070f8a1 254
255 case UPDATE:
5eaef520 256 /* see if row already exists */
257 if (v->field)
258 {
259 status = validate_row(q, Argv, v);
260 if (status != MR_EXISTS)
261 break;
b070f8a1 262 }
263
5eaef520 264 /* build "where" clause and perform update */
265 /* if q->rvar = NULL, perform post_rtn only */
266 if (q->rvar)
267 {
263a36d4 268 qual = build_qual(q->qual, q->argc, Argv);
5eaef520 269 incremental_before(q->rtable, qual, argv_ro);
270 status = do_update(q, &Argv[q->argc], qual, action, actarg);
271 incremental_after(q->rtable, qual, argv_ro);
272 if (status != MR_SUCCESS)
273 break;
274 flush_name(argv_ro[0], q->rtable);
275 table = table_name[q->rtable];
276 if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
277 {
278 EXEC SQL UPDATE tblstats
279 SET updates = updates + 1, modtime = SYSDATE
280 WHERE table_name = :table;
b070f8a1 281 }
282 }
283
5eaef520 284 /* execute followup routine (if any) */
285 if (v->post_rtn)
286 status = (*v->post_rtn)(q, Argv, cl);
b070f8a1 287
5eaef520 288 break;
b070f8a1 289
290 case APPEND:
5eaef520 291 /* see if row already exists */
292 if (v->field)
293 {
294 status = validate_row(q, Argv, v);
295 if (status != MR_NO_MATCH)
296 break;
b070f8a1 297 }
298
5eaef520 299 /* build "where" clause if needed */
300 if (q->qual)
263a36d4 301 qual = build_qual(q->qual, q->argc, Argv);
5eaef520 302
303 /* perform the append */
304 /* if q->rvar = NULL, perform post_rtn only */
305 if (q->rvar)
306 {
307 incremental_clear_before();
263a36d4 308 status = do_append(q, &Argv[q->argc], qual, action, actarg);
5eaef520 309 if (status != MR_SUCCESS)
310 break;
311 if (v && v->object_id)
312 {
263a36d4 313 qual = realloc(qual, 15 + strlen(q->rvar) +
314 strlen(Argv[q->argc + q->vcnt]));
5eaef520 315 sprintf(qual, "%s.%s = %s", q->rvar, v->object_id,
316 Argv[q->argc + q->vcnt]);
317 incremental_after(q->rtable, qual, argv_ro);
318 }
319 else
263a36d4 320 incremental_after(q->rtable, qual, argv_ro);
b070f8a1 321
5eaef520 322 table = table_name[q->rtable];
323 EXEC SQL UPDATE tblstats
324 SET appends = appends + 1, modtime = SYSDATE
325 WHERE table_name = :table;
b070f8a1 326 }
5eaef520 327
328 /* execute followup routine */
329 if (v->post_rtn)
330 status = (*v->post_rtn)(q, Argv, cl);
331 break;
b070f8a1 332
333 case DELETE:
5eaef520 334 /* see if row already exists */
335 if (v->field)
336 {
337 status = validate_row(q, Argv, v);
338 if (status != MR_EXISTS)
339 break;
b070f8a1 340 }
341
5eaef520 342 /* build "where" clause and perform delete */
343 /* if q->rvar = NULL, perform post_rtn only */
344 if (q->rvar)
345 {
263a36d4 346 qual = build_qual(q->qual, q->argc, Argv);
5eaef520 347 table = table_name[q->rtable];
348 incremental_before(q->rtable, qual, argv_ro);
349 status = do_delete(q, qual, action, actarg);
350 incremental_clear_after();
351 if (status != MR_SUCCESS)
352 break;
353 flush_name(argv_ro[0], q->rtable);
354 EXEC SQL UPDATE tblstats
355 SET deletes = deletes + 1, modtime = SYSDATE
356 WHERE table_name = :table;
b070f8a1 357 }
358
5eaef520 359 /* execute followup routine */
360 if (v->post_rtn)
361 status = (*v->post_rtn)(q, Argv, cl);
362 break;
7ac48069 363
364 case SPECIAL:
365 break;
b070f8a1 366 }
367
368out:
263a36d4 369 free(qual);
370
5eaef520 371 if (status == MR_SUCCESS && dbms_errno != 0)
372 {
373 com_err(whoami, MR_INTERNAL, "Server didn't notice DBMS ERROR %d",
374 dbms_errno);
375 status = mr_errcode;
b070f8a1 376 }
377
5eaef520 378 if (q->type == RETRIEVE)
379 EXEC SQL COMMIT WORK;
380 else
381 {
382 if (status == MR_SUCCESS)
383 {
384 EXEC SQL COMMIT WORK;
385 if (journal)
386 {
e688520a 387 char *buf;
5eaef520 388 int i;
389 extern time_t now;
390
391 fprintf(journal, "%% %s %s %s",
392 cl->clname, cl->entity, ctime(&now));
85330553 393 fprintf(journal, "%s ", q->name);
5eaef520 394 for (i = 0; i < argc; i++)
395 {
396 if (i != 0)
397 putc(' ', journal);
e688520a 398 buf = requote(argv_ro[i]);
5eaef520 399 fputs(buf, journal);
e688520a 400 free(buf);
b070f8a1 401 }
5eaef520 402 putc('\n', journal);
403 fflush(journal);
b070f8a1 404 }
5eaef520 405 incremental_update();
406 }
407 else
408 {
409 cache_abort();
410 EXEC SQL ROLLBACK WORK;
411 incremental_flush();
b070f8a1 412 }
413 }
5eaef520 414 cache_commit(); /* commit following abort is safe */
b070f8a1 415
85330553 416 if (status != MR_SUCCESS)
5eaef520 417 com_err(whoami, status, " (Query failed)");
418 return status;
b070f8a1 419}
420
263a36d4 421char *build_qual(char *fmt_buf, int argc, char *argv[])
b070f8a1 422{
263a36d4 423 char *res, *result_buf, *fmt, *arg, *like, *p;
424
425 result_buf = xmalloc(2 * (strlen(fmt_buf) + argc * ARGLEN));
426
427 res = result_buf;
428 fmt = fmt_buf;
429
430 like = strstr(fmt, "LIKE");
431 arg = strchr(fmt, '%');
5eaef520 432
263a36d4 433 /* Look through the format for LIKE expressions and arguments.
434 Substitute in the arguments, simplify the `LIKE's to `='s
435 where possible, and insert ESCAPE clauses where needed */
436
437 while (*fmt)
5eaef520 438 {
263a36d4 439 if (!like && !arg)
5eaef520 440 {
263a36d4 441 /* only plain text remains */
442 strcpy(res, fmt);
443 res = strchr(res, '\0');
444 break;
445 }
446 else if (!like || arg < like)
447 {
448 /* regular arg: copy up to arg, then substitute */
449 strncpy(res, fmt, arg - fmt);
450 res += arg - fmt;
451 if (*++arg)
5eaef520 452 {
263a36d4 453 switch (*arg++)
5eaef520 454 {
263a36d4 455 case '%':
456 *res++ = '%';
5eaef520 457 break;
263a36d4 458
5eaef520 459 case 's':
263a36d4 460 p = *argv;
461 /* copy string, doubling single quotes */
462 while (*p)
5eaef520 463 {
263a36d4 464 if (*p == '\'')
465 *res++ = '\'';
466 *res++ = *p++;
03c05291 467 }
5eaef520 468 argv++;
469 break;
263a36d4 470
5eaef520 471 case 'd':
472 res += sprintf(res, "%d", *(int *)*argv++);
473 break;
03c05291 474 }
5eaef520 475 }
263a36d4 476 fmt = arg;
477 arg = strchr(fmt, '%');
478 } else {
479 /* LIKE arg: copy over up to the arg, then copy and convert arg */
086d5715 480 int escape = 0, pattern = 0;
481 char *likepos = res + (like - fmt);
263a36d4 482
483 strncpy(res, fmt, arg - fmt);
484 res += arg - fmt;
485
486 /* copy arg, converting UNIX globs to `SQL voodoo', and noting
487 if we'll need an ESCAPE clause */
488 for (p = *argv++; *p; p++)
489 {
490 switch (*p)
491 {
492 case '*':
493 *res++ = '%';
494 *res++ = '%'; /* need to double for build_sql_stmt */
086d5715 495 pattern = 1;
263a36d4 496 break;
497
498 case '?':
499 *res++ = '_';
086d5715 500 pattern = 1;
263a36d4 501 break;
502
503 case '%':
504 case '_':
505 *res++ = '*';
506 *res++ = *p;
507 if (*p == '%')
508 *res++ = *p;
509 escape = 1;
510 break;
511
512 case '\'':
513 *res++ = '\'';
514 /* fall through */
515
516 default:
517 *res++ = *p;
518 }
519 }
520
086d5715 521 /* if no pattern characters, write over "LIKE" with " = " */
aa350a90 522 if (!pattern && !escape)
086d5715 523 memcpy(likepos, " = ", 4);
524
263a36d4 525 fmt = arg + 2;
aa350a90 526 while (*fmt && *fmt != ' ')
263a36d4 527 *res++ = *fmt++;
528
529 if (escape)
530 res += sprintf(res, " ESCAPE '*'");
531
532 arg = strchr(fmt, '%');
533 like = strstr(fmt, "LIKE");
5eaef520 534 }
b070f8a1 535 }
263a36d4 536
5eaef520 537 *res = '\0';
263a36d4 538 result_buf = realloc(result_buf, strlen(result_buf) + 1);
539 return result_buf;
b070f8a1 540}
541
b070f8a1 542/* Build arguement vector, verify query and arguments */
543
f1bc925a 544int privileged;
545
5eaef520 546int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
b070f8a1 547{
44d12d58 548 int argreq;
549 int status;
550 struct validate *v = q->validate;
551 int i;
552 char *to, *fr, *stop;
5eaef520 553
554 privileged = 0;
555
556 /* check argument count */
557 argreq = q->argc;
558 if (q->type == UPDATE || q->type == APPEND)
559 argreq += q->vcnt;
560 if (argc != argreq)
561 return MR_ARGS;
562
563 /* copy the arguments into a local argv that we can modify */
564 for (i = 0; i < argc; i++)
565 {
e688520a 566 for (to = Argv[i], fr = argv_ro[i], stop = to + MAX_FIELD_WIDTH; (*fr) && (to < stop);)
5eaef520 567 *to++ = *fr++;
568
569 if (*fr)
570 return MR_ARG_TOO_LONG;
571 *to = '\0';
572
85330553 573 if (to > Argv[i] && *--to == '\\')
5eaef520 574 return MR_BAD_CHAR;
b070f8a1 575 }
576
ce8337ff 577 /* check initial query access, unless we're acting as a proxy */
578 if (!cl->proxy_id)
579 {
580 status = check_query_access(q, Argv, cl);
581 if (status != MR_SUCCESS && status != MR_PERM)
582 return status;
583 if (status == MR_SUCCESS)
584 privileged++;
585 }
5eaef520 586
587 /* validate arguments */
588 if (v && v->valobj)
589 {
590 status = validate_fields(q, Argv, v->valobj, v->objcnt);
591 if (status != MR_SUCCESS)
592 return status;
b070f8a1 593 }
594
5eaef520 595 /* perform special query access check */
596 if (!privileged && v && v->acs_rtn)
597 {
598 status = (*v->acs_rtn)(q, Argv, cl);
599 if (status != MR_SUCCESS && status != MR_PERM)
600 return status;
601 if (status == MR_SUCCESS)
602 return MR_SUCCESS;
b070f8a1 603 }
604
5eaef520 605 return privileged ? MR_SUCCESS : MR_PERM;
b070f8a1 606}
607
608
609/* This routine caches info from the database. Each query acl is stored
610 * in the query structure, and whether that acl contains everybody.
611 */
612
5eaef520 613int check_query_access(struct query *q, char *argv[], client *cl)
048b1b94 614{
5eaef520 615 EXEC SQL BEGIN DECLARE SECTION;
616 char *name;
617 int acl_id;
618 static int def_uid;
619 EXEC SQL END DECLARE SECTION;
b070f8a1 620
5eaef520 621 /* initialize default uid */
622 if (def_uid == 0)
623 EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
624
625 /* get query access control list */
626 if (q->acl != 0)
627 acl_id = q->acl;
628 else
629 {
630 name = q->shortname;
631 EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
632 if (sqlca.sqlcode < 0)
633 return MR_DBMS_ERR;
634 if (sqlca.sqlcode == SQL_NO_MATCH)
635 return MR_PERM;
636 q->acl = acl_id;
637
638 /* check for default access */
639 EXEC SQL SELECT member_id INTO :acl_id FROM imembers
640 WHERE list_id = :acl_id AND member_type = 'USER'
641 AND member_id = :def_uid;
642 if (sqlca.sqlerrd[2] == 0)
643 q->everybody = 0;
644 else
645 q->everybody = 1;
b070f8a1 646 }
647
5eaef520 648 if (q->everybody)
649 return MR_SUCCESS;
b070f8a1 650
5eaef520 651 if (find_member("LIST", acl_id, cl))
652 return MR_SUCCESS;
653 else
654 return MR_PERM;
048b1b94 655}
b070f8a1 656
5eaef520 657int find_member(char *list_type, int list_id, client *cl)
048b1b94 658{
5eaef520 659 EXEC SQL BEGIN DECLARE SECTION;
660 int flag, users_id, client_id;
661 EXEC SQL END DECLARE SECTION;
662
663 if (!strcmp(strtrim(list_type), "USER") && list_id == cl->users_id)
664 return 1;
665
666 if (!strcmp(strtrim(list_type), "KERBEROS") && list_id == -cl->client_id)
667 return 1;
668
669 /* see if client is a member of list */
670 flag = 0;
671 users_id = cl->users_id;
672 client_id = -cl->client_id;
673 EXEC SQL SELECT COUNT(member_id) INTO :flag FROM imembers
674 WHERE list_id = :list_id
675 AND ( ( member_type = 'USER' AND member_id = :users_id )
676 OR (member_type = 'KERBEROS' AND member_id = :client_id ) );
677 if (sqlca.sqlcode == 0)
678 return flag;
679 return 0;
048b1b94 680}
b070f8a1 681
682
29028043 683int do_retrieve(struct query *q, char *pqual,
7ac48069 684 int (*action)(int, char *[], void *), void *actarg)
048b1b94 685{
5eaef520 686 build_sql_stmt(stmt_buf, "SELECT", q->tlist, NULL, pqual);
29028043 687 if (q->sort)
5eaef520 688 {
689 strcat(stmt_buf, " ORDER BY ");
29028043 690 strcat(stmt_buf, q->sort);
b070f8a1 691 }
692
7ac48069 693 return do_for_all_rows(stmt_buf, q->vcnt, action, actarg);
048b1b94 694}
695
5eaef520 696void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
697 char *argv[], char *qual)
048b1b94 698{
5eaef520 699 char fmt_buf[MR_STMTBUF_LEN];
44d12d58 700 char *res, *fmt;
5eaef520 701
702 if (qual)
703 sprintf(fmt_buf, "%s %s WHERE %s", cmd, targetlist, qual);
704 else
705 sprintf(fmt_buf, "%s %s", cmd, targetlist);
706
707 for (res = result_buf, fmt = fmt_buf; *fmt; fmt++)
708 {
709 if (*fmt == '%')
710 {
711 if (*++fmt)
712 {
713 switch (*fmt)
714 {
715 case '%': /* %% -> % */
716 *res++ = *fmt;
717 break;
718 case 's':
719 if (*argv[0])
720 {
721 char *p = *argv;
722 while (*p)
723 {
724 if (*p == '\'')
725 *res++ = '\''; /* double the ' */
726 *res++ = *p++;
03c05291 727 }
99e09b48 728 }
5eaef520 729 argv++;
730 break;
731 case 'd':
732 res += sprintf(res, "%d", *(int *)*argv++);
733 break;
734 default: /* Swallow other %? pairs */
735 break;
99e09b48 736 }
5eaef520 737 }
738 else
739 break;
740 }
741 else
742 *res++ = *fmt; /* text -> result buffer */
048b1b94 743 }
5eaef520 744 *res = '\0';
048b1b94 745}
b070f8a1 746
5eaef520 747int do_update(struct query *q, char *argv[], char *qual,
7ac48069 748 int (*action)(int, char *[], void *), void *actarg)
048b1b94 749{
5eaef520 750 build_sql_stmt(stmt_buf, "UPDATE", q->tlist, argv, qual);
751 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
752 if (mr_errcode)
753 return mr_errcode;
754 return MR_SUCCESS;
048b1b94 755}
b070f8a1 756
5eaef520 757int do_append(struct query *q, char *argv[], char *pqual,
7ac48069 758 int (*action)(int, char *[], void *), void *actarg)
048b1b94 759{
5eaef520 760 build_sql_stmt(stmt_buf, "INSERT", q->tlist, argv, pqual);
761 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
762 if (mr_errcode)
763 return mr_errcode;
764 return MR_SUCCESS;
048b1b94 765}
b070f8a1 766
7ac48069 767int do_delete(struct query *q, char *qual,
768 int (*action)(int, char *[], void *), void *actarg)
048b1b94 769{
5eaef520 770 sprintf(stmt_buf, "DELETE FROM %s WHERE %s", table_name[q->rtable], qual);
771 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
772 if (mr_errcode)
773 return mr_errcode;
774 return MR_SUCCESS;
048b1b94 775}
b070f8a1 776
777
778/**
779 ** set_next_object_id - set next object id in values table
780 **
781 ** Inputs: object - object name in values table and in objects
782 ** table - name of table objects are found in
1a41acb7 783 ** limit - should the ID be range limited
b070f8a1 784 **
785 ** - called before an APPEND operation to set the next object id to
786 ** be used for the new record to the next free value
787 **
788 **/
789
5eaef520 790int set_next_object_id(char *object, enum tables table, int limit)
048b1b94 791{
5eaef520 792 EXEC SQL BEGIN DECLARE SECTION;
793 int value;
794 char *obj = object;
795 EXEC SQL END DECLARE SECTION;
796 int starting_value;
797
798 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :obj;
799 if (sqlca.sqlerrd[2] != 1)
800 return MR_NO_ID;
801
802 starting_value = value;
803 while (1)
804 {
c1c77cfd 805#ifdef ULTRIX_ID_HOLE
806 if (limit && value > 31999 && value < 32768)
807 value = 32768;
808#endif
5eaef520 809 if (limit && value > MAX_ID_VALUE)
810 value = MIN_ID_VALUE;
811
812 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = %d",
813 object, table_name[table], object, value);
814 dosql(sqlbuffer);
815 if (sqlca.sqlcode < 0)
816 return mr_errcode;
817 if (sqlca.sqlcode == SQL_NO_MATCH)
818 break;
819
820 value++;
821 if (limit && value == starting_value)
822 {
823 com_err(whoami, 0, "All id values have been used");
824 return MR_NO_ID;
45bf7573 825 }
b070f8a1 826 }
827
85330553 828 com_err(whoami, 0, "setting ID %s to %d", object, value);
5eaef520 829 EXEC SQL UPDATE numvalues SET value = :value WHERE name = :obj;
830 return MR_SUCCESS;
048b1b94 831}
b070f8a1 832
833
834/* Turn a kerberos name into the user's ID of the account that principal
835 * owns. Sets the kerberos ID and user ID.
836 */
837
5eaef520 838int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
048b1b94 839{
5eaef520 840 EXEC SQL BEGIN DECLARE SECTION;
841 int u_id, k_id;
842 char *krbname;
843 EXEC SQL END DECLARE SECTION;
b070f8a1 844
5eaef520 845 krbname = name;
846 *kid = 0;
847 *uid = 0;
b070f8a1 848
5eaef520 849 EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
850 FROM krbmap km, strings str
851 WHERE km.string_id = str.string_id AND str.string = :krbname;
852 EXEC SQL COMMIT WORK;
048b1b94 853
5eaef520 854 if (dbms_errno)
855 return mr_errcode;
b070f8a1 856
5eaef520 857 if (sqlca.sqlerrd[2] == 1)
858 {
b070f8a1 859 *kid = -k_id;
5eaef520 860 *uid = u_id;
861 return MR_SUCCESS;
862 }
863
864 if (name_to_id(name, STRINGS_TABLE, &k_id) == MR_SUCCESS)
865 *kid = -k_id;
b070f8a1 866
5eaef520 867 if (!ok)
868 {
869 *uid = *kid;
870 return MR_SUCCESS;
b070f8a1 871 }
872
5eaef520 873 if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
874 *uid = 0;
b070f8a1 875
5eaef520 876 if (*kid == 0)
877 *kid = *uid;
878 if (dbms_errno)
879 return mr_errcode;
880 return MR_SUCCESS;
048b1b94 881}
b070f8a1 882
883
03c05291 884void sanity_check_queries(void)
b070f8a1 885{
44d12d58 886 int i;
5eaef520 887 int maxv = 0, maxa = 0;
b070f8a1 888
5eaef520 889#define MAX(x, y) ((x) > (y) ? (x) : (y))
b070f8a1 890
c44ddfa7 891 for (i = 0; i < QueryCount; i++)
5eaef520 892 {
c44ddfa7 893 maxv = MAX(maxv, Queries[i].vcnt);
894 maxa = MAX(maxa, Queries[i].argc);
895 max_version = MAX(max_version, Queries[i].version);
b070f8a1 896 }
5eaef520 897 if (MAX(maxv, maxa) > QMAXARGS)
898 {
899 com_err(whoami, 0, "A query has more args than QMAXARGS");
900 exit(1);
b070f8a1 901 }
902}
048b1b94 903
03c05291 904
905/* Generically do a SELECT, storing the results in the provided buffers */
906
5eaef520 907void dosql(char *buffers[])
03c05291 908{
5eaef520 909 int i, errcode = 0, errlen;
03c05291 910
911 EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
5eaef520 912 if (sqlca.sqlcode)
913 return;
03c05291 914 EXEC SQL DECLARE inc_crs CURSOR FOR inc_stmt;
915 EXEC SQL OPEN inc_crs;
916 mr_sqlda->N = QMAXARGS;
917 EXEC SQL DESCRIBE SELECT LIST FOR inc_stmt INTO mr_sqlda;
918 mr_sqlda->N = mr_sqlda->F;
5eaef520 919 for (i = 0; i < mr_sqlda->N; i++)
920 {
921 mr_sqlda->V[i] = buffers[i];
922 mr_sqlda->T[i] = 97;
e688520a 923 mr_sqlda->L[i] = MAX_FIELD_WIDTH;
5eaef520 924 }
03c05291 925 EXEC SQL FETCH inc_crs USING DESCRIPTOR mr_sqlda;
926
927 /* if we got an error from the FETCH, we have to preserve it or the
928 close will reset it and the caller will think nothing happened */
5eaef520 929 if (sqlca.sqlcode)
930 {
931 errcode = sqlca.sqlcode;
932 errlen = sqlca.sqlerrm.sqlerrml;
933 }
03c05291 934
935 EXEC SQL CLOSE inc_crs;
5eaef520 936 if (errcode)
937 {
938 sqlca.sqlcode = errcode;
939 sqlca.sqlerrm.sqlerrml = errlen;
940 }
03c05291 941}
942
7ac48069 943int do_for_all_rows(char *query, int count,
944 int (*action)(int, char *[], void *), void *actarg)
03c05291 945{
5eaef520 946 int i, rowcount = 0;
9450827a 947 EXEC SQL BEGIN DECLARE SECTION;
948 char *q = query;
949 EXEC SQL END DECLARE SECTION;
03c05291 950
9450827a 951 EXEC SQL PREPARE stmt FROM :q;
5eaef520 952 if (sqlca.sqlcode)
7ac48069 953 return MR_INTERNAL;
03c05291 954 EXEC SQL DECLARE curs CURSOR FOR stmt;
955 EXEC SQL OPEN curs;
956 mr_sqlda->N = count;
957 EXEC SQL DESCRIBE SELECT LIST FOR stmt INTO mr_sqlda;
958 mr_sqlda->N = mr_sqlda->F;
5eaef520 959 for (i = 0; i < mr_sqlda->N; i++)
960 {
961 mr_sqlda->V[i] = sqlbuffer[i];
962 mr_sqlda->T[i] = 97;
e688520a 963 mr_sqlda->L[i] = MAX_FIELD_WIDTH;
5eaef520 964 }
965
b131e4a0 966 while (rowcount < max_row_count)
5eaef520 967 {
968 EXEC SQL FETCH curs USING DESCRIPTOR mr_sqlda;
969 if (sqlca.sqlcode)
970 break;
971 (*action)(count, sqlbuffer, actarg);
972 rowcount++;
973 }
03c05291 974 EXEC SQL CLOSE curs;
5eaef520 975
976 if (mr_errcode)
977 return mr_errcode;
b131e4a0 978 if (rowcount == max_row_count)
979 {
980 critical_alert("moirad", "attempted query with too many rows");
981 return MR_NO_MEM;
982 }
983 else if (rowcount == 0)
984 return MR_NO_MATCH;
985 else
986 return MR_SUCCESS;
03c05291 987}
988
989
048b1b94 990/* eof:qrtn.dc */
This page took 0.257552 seconds and 5 git commands to generate.