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