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