]> andersk Git - moira.git/blame - server/qrtn.pc
use CODE=ANSI_C option to proc
[moira.git] / server / qrtn.pc
CommitLineData
1a41acb7 1/*
2 * $Source$
3 * $Author$
4 * $Header$
b070f8a1 5 *
1a41acb7 6 * Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
8 * <mit-copyright.h>.
5eaef520 9 *
b070f8a1 10 */
11
12#ifndef lint
048b1b94 13static char *rcsid_qrtn_dc = "$Header$";
b070f8a1 14#endif lint
15
16#include <mit-copyright.h>
cc0088db 17#include <string.h>
b070f8a1 18#include "mr_server.h"
03c05291 19#include "query.h"
048b1b94 20EXEC SQL INCLUDE sqlca; /* SQL Communications Area */
21EXEC SQL INCLUDE sqlda; /* SQL Descriptor Area */
22#include "qrtn.h"
23
03c05291 24SQLDA *mr_sqlda;
5eaef520 25EXEC SQL BEGIN DECLARE SECTION;
1741dca0 26int mr_sig_length;
5eaef520 27int idummy;
28char cdummy[MR_CDUMMY_LEN];
048b1b94 29char stmt_buf[MR_STMTBUF_LEN];
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
03c05291 45int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
46int do_retrieve(struct query *q, char *pqual, char *psort,
47 int (*action)(), char *actarg);
48int do_update(struct query *q, char *argv[], char *qual,
49 int (*action)(), char *actarg);
50int do_append(struct query *q, char *argv[], char *pqual,
51 int (*action)(), char *actarg);
52int do_delete(struct query *q, char *qual,
53 int (*action)(), char *actarg);
54void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
55 char *argv[], char *qual);
56char *build_sort(struct validate *v, char *sort);
57
58/* from qvalidate.dc */
59int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n);
60int validate_row(struct query *q, char *argv[], struct validate *v);
61
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 SQLDA *mr_alloc_sqlda();
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
5eaef520 138 q = get_query_by_name(name, cl->args->mr_version_no);
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[],
146 int (*action)(), char *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 {
166 list_queries(cl->args->mr_version_no, action, actarg);
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;
175 q = get_query_by_name(argv_ro[0], cl->args->mr_version_no);
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 */
183 q = get_query_by_name(name, cl->args->mr_version_no);
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 {
195 status = (*v->pre_rtn)(q, Argv, cl, 0);
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();
235 status = do_retrieve(q, pqual, psort, sq_save_args, (char *)sq);
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;
b070f8a1 367 }
368
369out:
5eaef520 370 if (status == MR_SUCCESS && dbms_errno != 0)
371 {
372 com_err(whoami, MR_INTERNAL, "Server didn't notice DBMS ERROR %d",
373 dbms_errno);
374 status = mr_errcode;
b070f8a1 375 }
376
5eaef520 377 if (q->type == RETRIEVE)
378 EXEC SQL COMMIT WORK;
379 else
380 {
381 if (status == MR_SUCCESS)
382 {
383 EXEC SQL COMMIT WORK;
384 if (journal)
385 {
386 char buf[1024];
387 int i;
388 extern time_t now;
389
390 fprintf(journal, "%% %s %s %s",
391 cl->clname, cl->entity, ctime(&now));
392 fprintf(journal, "%s[%d] ", q->name, cl->args->mr_version_no);
393 for (i = 0; i < argc; i++)
394 {
395 if (i != 0)
396 putc(' ', journal);
397 requote(buf, argv_ro[i], sizeof(buf));
398 fputs(buf, journal);
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
5eaef520 414 if (status != MR_SUCCESS && log_flags & LOG_RES)
415 com_err(whoami, status, " (Query failed)");
416 return status;
b070f8a1 417}
418
5eaef520 419int build_qual(char *fmt_buf, int argc, char *argv[], char *qual)
b070f8a1 420{
5eaef520 421 char *res, *fmt;
422
423 for (res = qual, fmt = fmt_buf; *fmt; fmt++)
424 {
425 if (*fmt == '%')
426 {
427 if (*++fmt)
428 {
429 switch (*fmt)
430 {
431 case '%': /* %% -> % */
432 *res++ = *fmt;
433 break;
434 case 's':
435 if (*argv[0])
436 {
437 char *p = *argv;
438 while (*p)
439 {
440 if (*p == '\'')
441 *res++ = '\''; /* double the ' */
442 *res++ = *p++;
03c05291 443 }
444 }
5eaef520 445 argv++;
446 break;
447 case 'd':
448 res += sprintf(res, "%d", *(int *)*argv++);
449 break;
450 default: /* Swallow other %? pairs */
03c05291 451 break;
452 }
5eaef520 453 }
454 else
455 break;
456 }
457 else
458 *res++ = *fmt; /* text -> result buffer */
b070f8a1 459 }
5eaef520 460 *res = '\0';
b070f8a1 461}
462
5eaef520 463char *build_sort(struct validate *v, char *sort)
b070f8a1 464{
44d12d58 465 struct valobj *vo;
466 int n;
5eaef520 467 char elem[16];
468
469 n = v->objcnt;
470 vo = v->valobj;
471 *sort = '\0';
472
473 while (--n >= 0)
474 {
475 if (vo->type == V_SORT)
476 {
477 sprintf(elem, "%d", vo->index + 1); /* Result column number */
478 if (*sort)
479 strcat(sort, ", ");
480 strcat(sort, elem);
b070f8a1 481 }
5eaef520 482 vo++;
b070f8a1 483 }
484
5eaef520 485 return (*sort) ? sort : 0;
b070f8a1 486}
487
488
489/* Build arguement vector, verify query and arguments */
490
f1bc925a 491int privileged;
492
5eaef520 493int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
b070f8a1 494{
44d12d58 495 int argreq;
496 int status;
497 struct validate *v = q->validate;
498 int i;
499 char *to, *fr, *stop;
5eaef520 500
501 privileged = 0;
502
503 /* check argument count */
504 argreq = q->argc;
505 if (q->type == UPDATE || q->type == APPEND)
506 argreq += q->vcnt;
507 if (argc != argreq)
508 return MR_ARGS;
509
510 /* copy the arguments into a local argv that we can modify */
511 for (i = 0; i < argc; i++)
512 {
513 for (to = Argv[i], fr = argv_ro[i], stop = to + ARGLEN; (*fr) && (to < stop);)
514 *to++ = *fr++;
515
516 if (*fr)
517 return MR_ARG_TOO_LONG;
518 *to = '\0';
519
520 if (*--to == '\\')
521 return MR_BAD_CHAR;
b070f8a1 522 }
523
5eaef520 524 /* check initial query access */
525 status = check_query_access(q, Argv, cl);
526 if (status != MR_SUCCESS && status != MR_PERM)
527 return status;
528 if (status == MR_SUCCESS)
529 privileged++;
530
531 /* validate arguments */
532 if (v && v->valobj)
533 {
534 status = validate_fields(q, Argv, v->valobj, v->objcnt);
535 if (status != MR_SUCCESS)
536 return status;
b070f8a1 537 }
538
5eaef520 539 /* perform special query access check */
540 if (!privileged && v && v->acs_rtn)
541 {
542 status = (*v->acs_rtn)(q, Argv, cl);
543 if (status != MR_SUCCESS && status != MR_PERM)
544 return status;
545 if (status == MR_SUCCESS)
546 return MR_SUCCESS;
b070f8a1 547 }
548
5eaef520 549 return privileged ? MR_SUCCESS : MR_PERM;
b070f8a1 550}
551
552
553/* This routine caches info from the database. Each query acl is stored
554 * in the query structure, and whether that acl contains everybody.
555 */
556
5eaef520 557int check_query_access(struct query *q, char *argv[], client *cl)
048b1b94 558{
5eaef520 559 EXEC SQL BEGIN DECLARE SECTION;
560 char *name;
561 int acl_id;
562 static int def_uid;
563 EXEC SQL END DECLARE SECTION;
b070f8a1 564
5eaef520 565 /* initialize default uid */
566 if (def_uid == 0)
567 EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
568
569 /* get query access control list */
570 if (q->acl != 0)
571 acl_id = q->acl;
572 else
573 {
574 name = q->shortname;
575 EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
576 if (sqlca.sqlcode < 0)
577 return MR_DBMS_ERR;
578 if (sqlca.sqlcode == SQL_NO_MATCH)
579 return MR_PERM;
580 q->acl = acl_id;
581
582 /* check for default access */
583 EXEC SQL SELECT member_id INTO :acl_id FROM imembers
584 WHERE list_id = :acl_id AND member_type = 'USER'
585 AND member_id = :def_uid;
586 if (sqlca.sqlerrd[2] == 0)
587 q->everybody = 0;
588 else
589 q->everybody = 1;
b070f8a1 590 }
591
5eaef520 592 if (q->everybody)
593 return MR_SUCCESS;
b070f8a1 594
5eaef520 595 if (find_member("LIST", acl_id, cl))
596 return MR_SUCCESS;
597 else
598 return MR_PERM;
048b1b94 599}
b070f8a1 600
601
5eaef520 602int find_member(char *list_type, int list_id, client *cl)
048b1b94 603{
5eaef520 604 EXEC SQL BEGIN DECLARE SECTION;
605 int flag, users_id, client_id;
606 EXEC SQL END DECLARE SECTION;
607
608 if (!strcmp(strtrim(list_type), "USER") && list_id == cl->users_id)
609 return 1;
610
611 if (!strcmp(strtrim(list_type), "KERBEROS") && list_id == -cl->client_id)
612 return 1;
613
614 /* see if client is a member of list */
615 flag = 0;
616 users_id = cl->users_id;
617 client_id = -cl->client_id;
618 EXEC SQL SELECT COUNT(member_id) INTO :flag FROM imembers
619 WHERE list_id = :list_id
620 AND ( ( member_type = 'USER' AND member_id = :users_id )
621 OR (member_type = 'KERBEROS' AND member_id = :client_id ) );
622 if (sqlca.sqlcode == 0)
623 return flag;
624 return 0;
048b1b94 625}
b070f8a1 626
627
5eaef520 628int do_retrieve(struct query *q, char *pqual, char *psort,
629 int (*action)(), char *actarg)
048b1b94 630{
5eaef520 631 build_sql_stmt(stmt_buf, "SELECT", q->tlist, NULL, pqual);
632 if (psort)
633 {
634 strcat(stmt_buf, " ORDER BY ");
635 strcat(stmt_buf, psort);
b070f8a1 636 }
637
5eaef520 638 return do_for_all_rows(stmt_buf, q->vcnt, action, (int)actarg);
048b1b94 639}
640
5eaef520 641char *sqlstrstr(char *str, char *pat)
cc0088db 642{
44d12d58 643 char *p = pat;
5eaef520 644
645 do
646 {
647 if (*str == '\'') /* Skip over single-quote delimited substrings */
648 {
649 while (*++str && (*str != '\''))
650 ;
651 continue;
cc0088db 652 }
5eaef520 653 if (*str == *p)
654 {
44d12d58 655 char *s;
5eaef520 656 s = str;
657 while (*++p && (*++s == *p))
658 ;
659 if (*p)
660 p = pat; /* failed */
cc0088db 661 }
5eaef520 662 }
663 while (*p && *++str);
cc0088db 664
5eaef520 665 if (!*str)
666 str = NULL;
667 return str;
cc0088db 668}
669
5eaef520 670void optimize_sql_stmt(char *buf)
cc0088db 671{
5eaef520 672 char *point = buf, *pat, *eopat, *esc1, *esc2, *csr;
673
674 for (point = buf; point = sqlstrstr(point, "LIKE"); point++)
675 {
676 /* Now pointing to string "LIKE" */
677
678 /* Look at next word */
679 for (pat = point + 4; *pat == ' '; pat++)
680 ;
681
682 /* Is it a single-quote delimited string? */
683 if (*pat != '\'')
684 continue;
685
686 /* look for "escape" clause - save escape character */
687 /* 1. Find end of pattern */
688 for (eopat = pat + 1; 1; eopat++)
689 {
690 if (*eopat == '\'')
691 {
692 if (eopat[1] == '\'') /* single-quote is self-escaping */
693 eopat++;
694 else
695 break;
cc0088db 696 }
697 }
698
5eaef520 699 /* 2. Look at next word */
700 for (esc1 = eopat; *++esc1 == ' ';)
701 ;
cc0088db 702
5eaef520 703 /* 3. esc1 = 0 if not "ESCAPE '?'", where the ? may be any character. */
704 if (strncmp(esc1, "ESCAPE", 6))
705 esc1 = NULL;
cc0088db 706
5eaef520 707 if (esc1)
708 {
709 for (esc2 = esc1 + 6; *esc2 == ' '; esc2++)
710 ;
cc0088db 711
5eaef520 712 if (*esc2++ != '\'')
713 continue; /* Bad SQL syntax. Skip. */
714 /* esc2 now points at the escape character itself */
715 if (esc2[1] != '\'')
716 continue; /* Weird escape string. Skip. */
717 }
718 else
719 esc2 = "\\";
720
721 /* Is pattern free from special characters? */
722 for (csr = pat; csr < eopat; csr++)
723 {
724 if ((*csr == '%') || (*csr == '_') || (*csr == *esc2))
725 break;
726 }
727 if (csr != eopat)
728 continue; /* Uses pattern matching. Skip. */
729
730 /* Optimize the query statement */
731 /* 1. Change "LIKE" to " = " */
732 memcpy(point, " = ", 4);
733
734 /* 2. Change "ESCAPE" to " " */
735 if (esc1)
736 {
737 memset(esc1, ' ', 6);
738 /* 3. Change "'*'" to " " */
739 /* (Changes '''' to " ") */
740 if (esc2)
741 memset(esc2 - 1, ' ', (*esc2 == '\'') ? 4 : 3);
cc0088db 742 }
743 }
744}
745
5eaef520 746void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
747 char *argv[], char *qual)
048b1b94 748{
5eaef520 749 char fmt_buf[MR_STMTBUF_LEN];
44d12d58 750 char *res, *fmt;
5eaef520 751
752 if (qual)
753 sprintf(fmt_buf, "%s %s WHERE %s", cmd, targetlist, qual);
754 else
755 sprintf(fmt_buf, "%s %s", cmd, targetlist);
756
757 for (res = result_buf, fmt = fmt_buf; *fmt; fmt++)
758 {
759 if (*fmt == '%')
760 {
761 if (*++fmt)
762 {
763 switch (*fmt)
764 {
765 case '%': /* %% -> % */
766 *res++ = *fmt;
767 break;
768 case 's':
769 if (*argv[0])
770 {
771 char *p = *argv;
772 while (*p)
773 {
774 if (*p == '\'')
775 *res++ = '\''; /* double the ' */
776 *res++ = *p++;
03c05291 777 }
99e09b48 778 }
5eaef520 779 argv++;
780 break;
781 case 'd':
782 res += sprintf(res, "%d", *(int *)*argv++);
783 break;
784 default: /* Swallow other %? pairs */
785 break;
99e09b48 786 }
5eaef520 787 }
788 else
789 break;
790 }
791 else
792 *res++ = *fmt; /* text -> result buffer */
048b1b94 793 }
5eaef520 794 *res = '\0';
cc0088db 795
5eaef520 796 optimize_sql_stmt(result_buf);
048b1b94 797}
b070f8a1 798
5eaef520 799int do_update(struct query *q, char *argv[], char *qual,
800 int (*action)(), char *actarg)
048b1b94 801{
5eaef520 802 build_sql_stmt(stmt_buf, "UPDATE", q->tlist, argv, qual);
803 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
804 if (mr_errcode)
805 return mr_errcode;
806 return MR_SUCCESS;
048b1b94 807}
b070f8a1 808
5eaef520 809int do_append(struct query *q, char *argv[], char *pqual,
810 int (*action)(), char *actarg)
048b1b94 811{
5eaef520 812 build_sql_stmt(stmt_buf, "INSERT", q->tlist, argv, pqual);
813 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
814 if (mr_errcode)
815 return mr_errcode;
816 return MR_SUCCESS;
048b1b94 817}
b070f8a1 818
5eaef520 819int do_delete(struct query *q, char *qual, int (*action)(), char *actarg)
048b1b94 820{
5eaef520 821 sprintf(stmt_buf, "DELETE FROM %s WHERE %s", table_name[q->rtable], qual);
822 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
823 if (mr_errcode)
824 return mr_errcode;
825 return MR_SUCCESS;
048b1b94 826}
b070f8a1 827
828
829/**
830 ** set_next_object_id - set next object id in values table
831 **
832 ** Inputs: object - object name in values table and in objects
833 ** table - name of table objects are found in
1a41acb7 834 ** limit - should the ID be range limited
b070f8a1 835 **
836 ** - called before an APPEND operation to set the next object id to
837 ** be used for the new record to the next free value
838 **
839 **/
840
5eaef520 841int set_next_object_id(char *object, enum tables table, int limit)
048b1b94 842{
5eaef520 843 EXEC SQL BEGIN DECLARE SECTION;
844 int value;
845 char *obj = object;
846 EXEC SQL END DECLARE SECTION;
847 int starting_value;
848
849 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :obj;
850 if (sqlca.sqlerrd[2] != 1)
851 return MR_NO_ID;
852
853 starting_value = value;
854 while (1)
855 {
856 if (limit && value > MAX_ID_VALUE)
857 value = MIN_ID_VALUE;
858
859 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = %d",
860 object, table_name[table], object, value);
861 dosql(sqlbuffer);
862 if (sqlca.sqlcode < 0)
863 return mr_errcode;
864 if (sqlca.sqlcode == SQL_NO_MATCH)
865 break;
866
867 value++;
868 if (limit && value == starting_value)
869 {
870 com_err(whoami, 0, "All id values have been used");
871 return MR_NO_ID;
45bf7573 872 }
b070f8a1 873 }
874
5eaef520 875 if (LOG_RES)
876 com_err(whoami, 0, "setting ID %s to %d", object, value);
877 EXEC SQL UPDATE numvalues SET value = :value WHERE name = :obj;
878 return MR_SUCCESS;
048b1b94 879}
b070f8a1 880
881
882/* Turn a kerberos name into the user's ID of the account that principal
883 * owns. Sets the kerberos ID and user ID.
884 */
885
5eaef520 886int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
048b1b94 887{
5eaef520 888 EXEC SQL BEGIN DECLARE SECTION;
889 int u_id, k_id;
890 char *krbname;
891 EXEC SQL END DECLARE SECTION;
b070f8a1 892
5eaef520 893 krbname = name;
894 *kid = 0;
895 *uid = 0;
b070f8a1 896
5eaef520 897 EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
898 FROM krbmap km, strings str
899 WHERE km.string_id = str.string_id AND str.string = :krbname;
900 EXEC SQL COMMIT WORK;
048b1b94 901
5eaef520 902 if (dbms_errno)
903 return mr_errcode;
b070f8a1 904
5eaef520 905 if (sqlca.sqlerrd[2] == 1)
906 {
b070f8a1 907 *kid = -k_id;
5eaef520 908 *uid = u_id;
909 return MR_SUCCESS;
910 }
911
912 if (name_to_id(name, STRINGS_TABLE, &k_id) == MR_SUCCESS)
913 *kid = -k_id;
b070f8a1 914
5eaef520 915 if (!ok)
916 {
917 *uid = *kid;
918 return MR_SUCCESS;
b070f8a1 919 }
920
5eaef520 921 if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
922 *uid = 0;
b070f8a1 923
5eaef520 924 if (*kid == 0)
925 *kid = *uid;
926 if (dbms_errno)
927 return mr_errcode;
928 return MR_SUCCESS;
048b1b94 929}
b070f8a1 930
931
932/* For now this just checks the argc's. It should also see that there
933 * are no duplicate names.
934 */
935
03c05291 936void sanity_check_queries(void)
b070f8a1 937{
44d12d58 938 int i;
5eaef520 939 int maxv = 0, maxa = 0;
940 extern int QueryCount2;
941 extern struct query Queries2[];
b070f8a1 942
5eaef520 943#define MAX(x, y) ((x) > (y) ? (x) : (y))
b070f8a1 944
5eaef520 945 for (i = 0; i < QueryCount2; i++)
946 {
947 maxv = MAX(maxv, Queries2[i].vcnt);
948 maxa = MAX(maxa, Queries2[i].argc);
b070f8a1 949 }
5eaef520 950 if (MAX(maxv, maxa) > QMAXARGS)
951 {
952 com_err(whoami, 0, "A query has more args than QMAXARGS");
953 exit(1);
b070f8a1 954 }
955}
048b1b94 956
03c05291 957
958/* Generically do a SELECT, storing the results in the provided buffers */
959
5eaef520 960void dosql(char *buffers[])
03c05291 961{
5eaef520 962 int i, errcode = 0, errlen;
03c05291 963
964 EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
5eaef520 965 if (sqlca.sqlcode)
966 return;
03c05291 967 EXEC SQL DECLARE inc_crs CURSOR FOR inc_stmt;
968 EXEC SQL OPEN inc_crs;
969 mr_sqlda->N = QMAXARGS;
970 EXEC SQL DESCRIBE SELECT LIST FOR inc_stmt INTO mr_sqlda;
971 mr_sqlda->N = mr_sqlda->F;
5eaef520 972 for (i = 0; i < mr_sqlda->N; i++)
973 {
974 mr_sqlda->V[i] = buffers[i];
975 mr_sqlda->T[i] = 97;
976 mr_sqlda->L[i] = ARGLEN;
977 }
03c05291 978 EXEC SQL FETCH inc_crs USING DESCRIPTOR mr_sqlda;
979
980 /* if we got an error from the FETCH, we have to preserve it or the
981 close will reset it and the caller will think nothing happened */
5eaef520 982 if (sqlca.sqlcode)
983 {
984 errcode = sqlca.sqlcode;
985 errlen = sqlca.sqlerrm.sqlerrml;
986 }
03c05291 987
988 EXEC SQL CLOSE inc_crs;
5eaef520 989 if (errcode)
990 {
991 sqlca.sqlcode = errcode;
992 sqlca.sqlerrm.sqlerrml = errlen;
993 }
03c05291 994}
995
5eaef520 996int do_for_all_rows(char *query, int count, int (*action)(), int actarg)
03c05291 997{
5eaef520 998 int i, rowcount = 0;
9450827a 999 EXEC SQL BEGIN DECLARE SECTION;
1000 char *q = query;
1001 EXEC SQL END DECLARE SECTION;
03c05291 1002
9450827a 1003 EXEC SQL PREPARE stmt FROM :q;
5eaef520 1004 if (sqlca.sqlcode)
1005 return;
03c05291 1006 EXEC SQL DECLARE curs CURSOR FOR stmt;
1007 EXEC SQL OPEN curs;
1008 mr_sqlda->N = count;
1009 EXEC SQL DESCRIBE SELECT LIST FOR stmt INTO mr_sqlda;
1010 mr_sqlda->N = mr_sqlda->F;
5eaef520 1011 for (i = 0; i < mr_sqlda->N; i++)
1012 {
1013 mr_sqlda->V[i] = sqlbuffer[i];
1014 mr_sqlda->T[i] = 97;
1015 mr_sqlda->L[i] = ARGLEN;
1016 }
1017
1018 while (1)
1019 {
1020 EXEC SQL FETCH curs USING DESCRIPTOR mr_sqlda;
1021 if (sqlca.sqlcode)
1022 break;
1023 (*action)(count, sqlbuffer, actarg);
1024 rowcount++;
1025 }
03c05291 1026 EXEC SQL CLOSE curs;
5eaef520 1027
1028 if (mr_errcode)
1029 return mr_errcode;
1030 return (rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS;
03c05291 1031}
1032
1033
048b1b94 1034/* eof:qrtn.dc */
This page took 0.23246 seconds and 5 git commands to generate.