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