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