]> andersk Git - moira.git/blob - server/qrtn.pc
4f0f9fecb47dc242a7e220729bba49c8ee0a81f0
[moira.git] / server / qrtn.pc
1 /* $Id$
2  *
3  * Query-processing routines
4  *
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>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13 #include "qrtn.h"
14 #include "query.h"
15
16 #include <stdlib.h>
17 #include <string.h>
18
19 EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
20 EXEC SQL INCLUDE sqlda;  /* SQL Descriptor Area */
21
22 RCSID("$Header$");
23
24 SQLDA *mr_sqlda;
25 EXEC SQL BEGIN DECLARE SECTION;
26 int mr_sig_length;
27 int idummy;
28 char cdummy[MR_CDUMMY_LEN];
29 char stmt_buf[MR_STMTBUF_LEN];
30 EXEC SQL END DECLARE SECTION;
31
32 char *Argv[QMAXARGS];
33 extern char *table_name[];
34 extern char *sqlbuffer[QMAXARGS];
35
36 int dbms_errno = 0;
37 int mr_errcode = 0;
38 EXEC SQL BEGIN DECLARE SECTION;
39 int query_timeout = 30;
40 char *database = "moira";
41 EXEC SQL END DECLARE SECTION;
42 extern char *whoami;
43 extern FILE *journal;
44
45 int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
46 int do_retrieve(struct query *q, char *pqual, char *psort,
47                 int (*action)(int, char *[], void *), void *actarg);
48 int do_update(struct query *q, char *argv[], char *qual,
49               int (*action)(int, char *[], void *), void *actarg);
50 int do_append(struct query *q, char *argv[], char *pqual,
51               int (*action)(int, char *[], void *), void *actarg);
52 int do_delete(struct query *q, char *qual,
53               int (*action)(int, char *[], void *), void *actarg);
54 void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
55                     char *argv[], char *qual);
56 char *build_sort(struct validate *v, char *sort);
57 char *sqlstrstr(char *str, char *pat);
58 void optimize_sql_stmt(char *buf);
59
60 SQLDA *mr_alloc_sqlda(void);
61 void sqlglm(char *, int *, int *);
62
63 /*
64  * dbmserr: Called when the DBMS indicates an error.
65  */
66
67 void dbmserr(void)
68 {
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);
82 }
83
84 /* This is declarative, not executed.  Applies from here on, in this file. */
85 EXEC SQL WHENEVER SQLERROR DO dbmserr();
86
87 int mr_open_database(void)
88 {
89   int i;
90   static first_open = 1;
91
92   if (first_open)
93     {
94       first_open = 0;
95
96       /* initialize local argv */
97       for (i = 0; i < 16; i++)
98         Argv[i] = malloc(ARGLEN);
99
100       mr_sqlda = mr_alloc_sqlda();
101
102       incremental_init();
103       flush_cache();
104     }
105
106   dbms_errno = 0;
107   mr_errcode = 0;
108
109   /* open the database */
110   EXEC SQL CONNECT :database IDENTIFIED BY :database;
111
112   if (dbms_errno)
113     return mr_errcode;
114
115   EXEC SQL SELECT data_length INTO :mr_sig_length FROM user_tab_columns
116     WHERE table_name = 'USERS' and column_name = 'SIGNATURE';
117   EXEC SQL COMMIT WORK;
118   if (dbms_errno)
119     return mr_errcode;
120
121   return MR_SUCCESS;
122 }
123
124 void mr_close_database(void)
125 {
126   flush_cache();
127   EXEC SQL COMMIT RELEASE;
128 }
129
130 int mr_check_access(client *cl, char *name, int argc, char *argv_ro[])
131 {
132   struct query *q;
133
134   dbms_errno = 0;
135   mr_errcode = 0;
136
137   q = get_query_by_name(name, cl->args->mr_version_no);
138   if (!q)
139     return MR_NO_HANDLE;
140
141   return mr_verify_query(cl, q, argc, argv_ro);
142 }
143
144 int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
145                      int (*action)(int, char *[], void *), void *actarg)
146 {
147   struct query *q;
148   int status;
149   struct validate *v;
150   char qual[256];
151   char sort[32];
152   char *pqual;
153   char *psort;
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;
161
162   /* list queries command */
163   if (!strcmp(name, "_list_queries"))
164     {
165       list_queries(cl->args->mr_version_no, action, actarg);
166       return MR_SUCCESS;
167     }
168
169   /* help query command */
170   if (!strcmp(name, "_help"))
171     {
172       if (argc < 1)
173         return MR_ARGS;
174       q = get_query_by_name(argv_ro[0], cl->args->mr_version_no);
175       if (!q)
176         return MR_NO_HANDLE;
177       help_query(q, action, actarg);
178       return MR_SUCCESS;
179     }
180
181   /* get query structure, return error if named query does not exist */
182   q = get_query_by_name(name, cl->args->mr_version_no);
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     {
194       status = (*v->pre_rtn)(q, Argv, cl);
195       if (status != MR_SUCCESS)
196         goto out;
197     }
198
199   switch (q->type)
200     {
201     case RETRIEVE:
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;
209         }
210
211       /* build "where" clause if needed */
212       if (q->qual)
213         {
214           build_qual(q->qual, q->argc, Argv, qual);
215           pqual = qual;
216         }
217       else
218         pqual = 0;
219
220       /* build "sort" clause if needed */
221       if (v && v->valobj)
222         psort = build_sort(v, sort);
223       else
224         psort = 0;
225
226       /* if there is a followup routine, then we must save the results */
227       /* of the first query for use by the followup routine */
228       /* if q->rvar = NULL, perform post_rtn only */
229       if (q->rvar)
230         {
231           if (v && v->post_rtn)
232             {
233               sq = sq_create();
234               status = do_retrieve(q, pqual, psort, sq_save_args, sq);
235               if (status != MR_SUCCESS)
236                 {
237                   sq_destroy(sq);
238                   break;
239                 }
240               status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
241             }
242           else
243             {
244               /* normal retrieve */
245               status = do_retrieve(q, pqual, psort, action, actarg);
246             }
247           if (status != MR_SUCCESS)
248             break;
249         }
250       else
251         status = (*v->post_rtn)(q, Argv, cl, action, actarg);
252
253       break;
254
255     case UPDATE:
256       /* see if row already exists */
257       if (v->field)
258         {
259           status = validate_row(q, Argv, v);
260           if (status != MR_EXISTS)
261             break;
262         }
263
264       /* build "where" clause and perform update */
265       /* if q->rvar = NULL, perform post_rtn only */
266       if (q->rvar)
267         {
268           build_qual(q->qual, q->argc, Argv, qual);
269           incremental_before(q->rtable, qual, argv_ro);
270           status = do_update(q, &Argv[q->argc], qual, action, actarg);
271           incremental_after(q->rtable, qual, argv_ro);
272           if (status != MR_SUCCESS)
273             break;
274           flush_name(argv_ro[0], q->rtable);
275           table = table_name[q->rtable];
276           if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
277             {
278               EXEC SQL UPDATE tblstats
279                 SET updates = updates + 1, modtime = SYSDATE
280                 WHERE table_name = :table;
281             }
282         }
283
284       /* execute followup routine (if any) */
285       if (v->post_rtn)
286         status = (*v->post_rtn)(q, Argv, cl);
287
288       break;
289
290     case APPEND:
291       /* see if row already exists */
292       if (v->field)
293         {
294           status = validate_row(q, Argv, v);
295           if (status != MR_NO_MATCH)
296             break;
297         }
298
299       /* build "where" clause if needed */
300       if (q->qual)
301         {
302           build_qual(q->qual, q->argc, Argv, qual);
303           pqual = qual;
304         }
305       else
306         pqual = 0;
307
308       /* perform the append */
309       /* if q->rvar = NULL, perform post_rtn only */
310       if (q->rvar)
311         {
312           incremental_clear_before();
313           status = do_append(q, &Argv[q->argc], pqual, action, actarg);
314           if (status != MR_SUCCESS)
315             break;
316           if (v && v->object_id)
317             {
318               sprintf(qual, "%s.%s = %s", q->rvar, v->object_id,
319                       Argv[q->argc + q->vcnt]);
320               incremental_after(q->rtable, qual, argv_ro);
321             }
322           else
323             incremental_after(q->rtable, pqual, argv_ro);
324
325           table = table_name[q->rtable];
326           EXEC SQL UPDATE tblstats
327             SET appends = appends + 1, modtime = SYSDATE
328             WHERE table_name = :table;
329         }
330
331       /* execute followup routine */
332       if (v->post_rtn)
333         status = (*v->post_rtn)(q, Argv, cl);
334       break;
335
336     case DELETE:
337       /* see if row already exists */
338       if (v->field)
339         {
340           status = validate_row(q, Argv, v);
341           if (status != MR_EXISTS)
342             break;
343         }
344
345       /* build "where" clause and perform delete */
346       /* if q->rvar = NULL, perform post_rtn only */
347       if (q->rvar)
348         {
349           build_qual(q->qual, q->argc, Argv, qual);
350           table = table_name[q->rtable];
351           incremental_before(q->rtable, qual, argv_ro);
352           status = do_delete(q, qual, action, actarg);
353           incremental_clear_after();
354           if (status != MR_SUCCESS)
355             break;
356           flush_name(argv_ro[0], q->rtable);
357           EXEC SQL UPDATE tblstats
358             SET deletes = deletes + 1, modtime = SYSDATE
359             WHERE table_name = :table;
360         }
361
362       /* execute followup routine */
363       if (v->post_rtn)
364         status = (*v->post_rtn)(q, Argv, cl);
365       break;
366
367     case SPECIAL:
368       break;
369     }
370
371 out:
372   if (status == MR_SUCCESS && dbms_errno != 0)
373     {
374       com_err(whoami, MR_INTERNAL, "Server didn't notice DBMS ERROR %d",
375               dbms_errno);
376       status = mr_errcode;
377     }
378
379   if (q->type == RETRIEVE)
380     EXEC SQL COMMIT WORK;
381   else
382     {
383       if (status == MR_SUCCESS)
384         {
385           EXEC SQL COMMIT WORK;
386           if (journal)
387             {
388               char buf[1024];
389               int i;
390               extern time_t now;
391
392               fprintf(journal, "%% %s %s %s",
393                       cl->clname, cl->entity, ctime(&now));
394               fprintf(journal, "%s[%ld] ", q->name, cl->args->mr_version_no);
395               for (i = 0; i < argc; i++)
396                 {
397                   if (i != 0)
398                     putc(' ', journal);
399                   requote(buf, argv_ro[i], sizeof(buf));
400                   fputs(buf, journal);
401                 }
402               putc('\n', journal);
403               fflush(journal);
404             }
405           incremental_update();
406         }
407       else
408         {
409           cache_abort();
410           EXEC SQL ROLLBACK WORK;
411           incremental_flush();
412         }
413     }
414   cache_commit(); /* commit following abort is safe */
415
416   if (status != MR_SUCCESS && log_flags & LOG_RES)
417     com_err(whoami, status, " (Query failed)");
418   return status;
419 }
420
421 void build_qual(char *fmt_buf, int argc, char *argv[], char *qual)
422 {
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++;
445                         }
446                     }
447                   argv++;
448                   break;
449                 case 'd':
450                   res += sprintf(res, "%d", *(int *)*argv++);
451                   break;
452                 default:                        /* Swallow other %? pairs */
453                     break;
454                 }
455             }
456           else
457             break;
458         }
459       else
460         *res++ = *fmt;                          /* text -> result buffer */
461     }
462   *res = '\0';
463 }
464
465 char *build_sort(struct validate *v, char *sort)
466 {
467   struct valobj *vo;
468   int n;
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);
483         }
484       vo++;
485     }
486
487   return (*sort) ? sort : 0;
488 }
489
490
491 /* Build arguement vector, verify query and arguments */
492
493 int privileged;
494
495 int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
496 {
497   int argreq;
498   int status;
499   struct validate *v = q->validate;
500   int i;
501   char *to, *fr, *stop;
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     {
515       for (to = Argv[i], fr = argv_ro[i], stop = to + ARGLEN; (*fr) && (to < stop);)
516         *to++ = *fr++;
517
518       if (*fr)
519         return MR_ARG_TOO_LONG;
520       *to = '\0';
521
522       if (*--to == '\\')
523         return MR_BAD_CHAR;
524     }
525
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;
539     }
540
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;
549     }
550
551   return privileged ? MR_SUCCESS : MR_PERM;
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
559 int check_query_access(struct query *q, char *argv[], client *cl)
560 {
561   EXEC SQL BEGIN DECLARE SECTION;
562   char *name;
563   int acl_id;
564   static int def_uid;
565   EXEC SQL END DECLARE SECTION;
566
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;
592     }
593
594   if (q->everybody)
595     return MR_SUCCESS;
596
597   if (find_member("LIST", acl_id, cl))
598     return MR_SUCCESS;
599   else
600     return MR_PERM;
601 }
602
603
604 int find_member(char *list_type, int list_id, client *cl)
605 {
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;
627 }
628
629
630 int do_retrieve(struct query *q, char *pqual, char *psort,
631                 int (*action)(int, char *[], void *), void *actarg)
632 {
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);
638     }
639
640   return do_for_all_rows(stmt_buf, q->vcnt, action, actarg);
641 }
642
643 char *sqlstrstr(char *str, char *pat)
644 {
645   char *p = pat;
646
647   do
648     {
649       if (*str == '\'')    /* Skip over single-quote delimited substrings */
650         {
651           while (*++str && (*str != '\''))
652             ;
653           continue;
654         }
655       if (*str == *p)
656         {
657           char *s;
658           s = str;
659           while (*++p && (*++s == *p))
660             ;
661           if (*p)
662             p = pat;  /* failed */
663         }
664     }
665   while (*p && *++str);
666
667   if (!*str)
668     str = NULL;
669   return str;
670 }
671
672 void optimize_sql_stmt(char *buf)
673 {
674   char *point = buf, *pat, *eopat, *esc1, *esc2, *csr;
675
676   for (point = buf; (point = sqlstrstr(point, "LIKE")); point++)
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;
698             }
699         }
700
701       /* 2. Look at next word */
702       for (esc1 = eopat; *++esc1 == ' ';)
703         ;
704
705       /* 3. esc1 = 0 if not "ESCAPE '?'", where the ? may be any character. */
706       if (strncmp(esc1, "ESCAPE", 6))
707         esc1 = NULL;
708
709       if (esc1)
710         {
711           for (esc2 = esc1 + 6; *esc2 == ' '; esc2++)
712             ;
713
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);
744         }
745     }
746 }
747
748 void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
749                     char *argv[], char *qual)
750 {
751   char fmt_buf[MR_STMTBUF_LEN];
752   char *res, *fmt;
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++;
779                         }
780                     }
781                   argv++;
782                   break;
783                 case 'd':
784                   res += sprintf(res, "%d", *(int *)*argv++);
785                   break;
786                 default:                        /* Swallow other %? pairs */
787                   break;
788                 }
789             }
790           else
791             break;
792         }
793       else
794         *res++ = *fmt;                          /* text -> result buffer */
795     }
796   *res = '\0';
797
798   optimize_sql_stmt(result_buf);
799 }
800
801 int do_update(struct query *q, char *argv[], char *qual,
802               int (*action)(int, char *[], void *), void *actarg)
803 {
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;
809 }
810
811 int do_append(struct query *q, char *argv[], char *pqual,
812               int (*action)(int, char *[], void *), void *actarg)
813 {
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;
819 }
820
821 int do_delete(struct query *q, char *qual,
822               int (*action)(int, char *[], void *), void *actarg)
823 {
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;
829 }
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
837  **         limit - should the ID be range limited
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
844 int set_next_object_id(char *object, enum tables table, int limit)
845 {
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;
875         }
876     }
877
878   if (LOG_RES)
879     com_err(whoami, 0, "setting ID %s to %d", object, value);
880   EXEC SQL UPDATE numvalues SET value = :value WHERE name = :obj;
881   return MR_SUCCESS;
882 }
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
889 int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
890 {
891   EXEC SQL BEGIN DECLARE SECTION;
892   int u_id, k_id;
893   char *krbname;
894   EXEC SQL END DECLARE SECTION;
895
896   krbname = name;
897   *kid = 0;
898   *uid = 0;
899
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;
904
905   if (dbms_errno)
906     return mr_errcode;
907
908   if (sqlca.sqlerrd[2] == 1)
909     {
910       *kid = -k_id;
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;
917
918   if (!ok)
919     {
920       *uid = *kid;
921       return MR_SUCCESS;
922     }
923
924   if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
925     *uid = 0;
926
927   if (*kid == 0)
928     *kid = *uid;
929   if (dbms_errno)
930     return mr_errcode;
931   return MR_SUCCESS;
932 }
933
934
935 /* For now this just checks the argc's.  It should also see that there
936  * are no duplicate names.
937  */
938
939 void sanity_check_queries(void)
940 {
941   int i;
942   int maxv = 0, maxa = 0;
943   extern int QueryCount2;
944   extern struct query Queries2[];
945
946 #define MAX(x, y) ((x) > (y) ? (x) : (y))
947
948   for (i = 0; i < QueryCount2; i++)
949     {
950       maxv = MAX(maxv, Queries2[i].vcnt);
951       maxa = MAX(maxa, Queries2[i].argc);
952     }
953   if (MAX(maxv, maxa) > QMAXARGS)
954     {
955       com_err(whoami, 0, "A query has more args than QMAXARGS");
956       exit(1);
957     }
958 }
959
960
961 /* Generically do a SELECT, storing the results in the provided buffers */
962
963 void dosql(char *buffers[])
964 {
965   int i, errcode = 0, errlen;
966
967   EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
968   if (sqlca.sqlcode)
969     return;
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;
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     }
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 */
985   if (sqlca.sqlcode)
986     {
987       errcode = sqlca.sqlcode;
988       errlen = sqlca.sqlerrm.sqlerrml;
989     }
990
991   EXEC SQL CLOSE inc_crs;
992   if (errcode)
993     {
994       sqlca.sqlcode = errcode;
995       sqlca.sqlerrm.sqlerrml = errlen;
996     }
997 }
998
999 int do_for_all_rows(char *query, int count,
1000                     int (*action)(int, char *[], void *), void *actarg)
1001 {
1002   int i, rowcount = 0;
1003   EXEC SQL BEGIN DECLARE SECTION;
1004   char *q = query;
1005   EXEC SQL END DECLARE SECTION;
1006
1007   EXEC SQL PREPARE stmt FROM :q;
1008   if (sqlca.sqlcode)
1009     return MR_INTERNAL;
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;
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     }
1030   EXEC SQL CLOSE curs;
1031
1032   if (mr_errcode)
1033     return mr_errcode;
1034   return (rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS;
1035 }
1036
1037
1038 /* eof:qrtn.dc */
This page took 0.455766 seconds and 3 git commands to generate.