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