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