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