]> andersk Git - moira.git/blob - server/qrtn.pc
Code style cleanup. (No functional changes)
[moira.git] / server / qrtn.pc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
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>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qrtn_dc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include <string.h>
18 #include "mr_server.h"
19 #include "query.h"
20 EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
21 EXEC SQL INCLUDE sqlda;  /* SQL Descriptor Area */
22 #include "qrtn.h"
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)(), char *actarg);
48 int do_update(struct query *q, char *argv[], char *qual,
49               int (*action)(), char *actarg);
50 int do_append(struct query *q, char *argv[], char *pqual,
51               int (*action)(), char *actarg);
52 int do_delete(struct query *q, char *qual,
53               int (*action)(), char *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
58 /* from qvalidate.dc */
59 int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n);
60 int validate_row(struct query *q, char *argv[], struct validate *v);
61
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   register int i;
90   SQLDA *mr_alloc_sqlda();
91   static first_open = 1;
92
93   if (first_open)
94     {
95       first_open = 0;
96
97       /* initialize local argv */
98       for (i = 0; i < 16; i++)
99         Argv[i] = malloc(ARGLEN);
100
101       mr_sqlda = mr_alloc_sqlda();
102
103       incremental_init();
104       flush_cache();
105     }
106
107   dbms_errno = 0;
108   mr_errcode = 0;
109
110   /* open the database */
111   EXEC SQL CONNECT :database IDENTIFIED BY :database;
112
113   if (dbms_errno)
114     return mr_errcode;
115
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;
123 }
124
125 void mr_close_database(void)
126 {
127   flush_cache();
128   EXEC SQL COMMIT RELEASE;
129 }
130
131 int mr_check_access(client *cl, char *name, int argc, char *argv_ro[])
132 {
133   struct query *q;
134
135   dbms_errno = 0;
136   mr_errcode = 0;
137
138   q = get_query_by_name(name, cl->args->mr_version_no);
139   if (!q)
140     return MR_NO_HANDLE;
141
142   return mr_verify_query(cl, q, argc, argv_ro);
143 }
144
145 int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
146                      int (*action)(), char *actarg)
147 {
148   register struct query *q;
149   register int status;
150   register struct validate *v;
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;
162
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;
168     }
169
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     }
181
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)
197         goto out;
198     }
199
200   switch (q->type)
201     {
202     case RETRIEVE:
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;
210         }
211
212       /* build "where" clause if needed */
213       if (q->qual)
214         {
215           build_qual(q->qual, q->argc, Argv, qual);
216           pqual = qual;
217         }
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;
240                 }
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);
247             }
248           if (status != MR_SUCCESS)
249             break;
250         }
251       else
252         status = (*v->post_rtn)(q, Argv, cl, action, actarg);
253
254       break;
255
256     case UPDATE:
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;
263         }
264
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;
282             }
283         }
284
285       /* execute followup routine (if any) */
286       if (v->post_rtn)
287         status = (*v->post_rtn)(q, Argv, cl);
288
289       break;
290
291     case APPEND:
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;
298         }
299
300       /* build "where" clause if needed */
301       if (q->qual)
302         {
303           build_qual(q->qual, q->argc, Argv, qual);
304           pqual = qual;
305         }
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);
325
326           table = table_name[q->rtable];
327           EXEC SQL UPDATE tblstats
328             SET appends = appends + 1, modtime = SYSDATE
329             WHERE table_name = :table;
330         }
331
332       /* execute followup routine */
333       if (v->post_rtn)
334         status = (*v->post_rtn)(q, Argv, cl);
335       break;
336
337     case DELETE:
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;
344         }
345
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;
361         }
362
363       /* execute followup routine */
364       if (v->post_rtn)
365         status = (*v->post_rtn)(q, Argv, cl);
366       break;
367     }
368
369 out:
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;
375     }
376
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);
399                 }
400               putc('\n', journal);
401               fflush(journal);
402             }
403           incremental_update();
404         }
405       else
406         {
407           cache_abort();
408           EXEC SQL ROLLBACK WORK;
409           incremental_flush();
410         }
411     }
412   cache_commit(); /* commit following abort is safe */
413
414   if (status != MR_SUCCESS && log_flags & LOG_RES)
415     com_err(whoami, status, " (Query failed)");
416   return status;
417 }
418
419 int build_qual(char *fmt_buf, int argc, char *argv[], char *qual)
420 {
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++;
443                         }
444                     }
445                   argv++;
446                   break;
447                 case 'd':
448                   res += sprintf(res, "%d", *(int *)*argv++);
449                   break;
450                 default:                        /* Swallow other %? pairs */
451                     break;
452                 }
453             }
454           else
455             break;
456         }
457       else
458         *res++ = *fmt;                          /* text -> result buffer */
459     }
460   *res = '\0';
461 }
462
463 char *build_sort(struct validate *v, char *sort)
464 {
465   register struct valobj *vo;
466   register int n;
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);
481         }
482       vo++;
483     }
484
485   return (*sort) ? sort : 0;
486 }
487
488
489 /* Build arguement vector, verify query and arguments */
490
491 int privileged;
492
493 int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
494 {
495   register int argreq;
496   register int status;
497   register struct validate *v = q->validate;
498   register int i;
499   register char *to, *fr, *stop;
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;
522     }
523
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;
537     }
538
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;
547     }
548
549   return privileged ? MR_SUCCESS : MR_PERM;
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
557 int check_query_access(struct query *q, char *argv[], client *cl)
558 {
559   EXEC SQL BEGIN DECLARE SECTION;
560   char *name;
561   int acl_id;
562   static int def_uid;
563   EXEC SQL END DECLARE SECTION;
564
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;
590     }
591
592   if (q->everybody)
593     return MR_SUCCESS;
594
595   if (find_member("LIST", acl_id, cl))
596     return MR_SUCCESS;
597   else
598     return MR_PERM;
599 }
600
601
602 int find_member(char *list_type, int list_id, client *cl)
603 {
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;
625 }
626
627
628 int do_retrieve(struct query *q, char *pqual, char *psort,
629                 int (*action)(), char *actarg)
630 {
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);
636     }
637
638   return do_for_all_rows(stmt_buf, q->vcnt, action, (int)actarg);
639 }
640
641 char *sqlstrstr(char *str, char *pat)
642 {
643   register char *p = pat;
644
645   do
646     {
647       if (*str == '\'')    /* Skip over single-quote delimited substrings */
648         {
649           while (*++str && (*str != '\''))
650             ;
651           continue;
652         }
653       if (*str == *p)
654         {
655           register char *s;
656           s = str;
657           while (*++p && (*++s == *p))
658             ;
659           if (*p)
660             p = pat;  /* failed */
661         }
662     }
663   while (*p && *++str);
664
665   if (!*str)
666     str = NULL;
667   return str;
668 }
669
670 void optimize_sql_stmt(char *buf)
671 {
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;
696             }
697         }
698
699       /* 2. Look at next word */
700       for (esc1 = eopat; *++esc1 == ' ';)
701         ;
702
703       /* 3. esc1 = 0 if not "ESCAPE '?'", where the ? may be any character. */
704       if (strncmp(esc1, "ESCAPE", 6))
705         esc1 = NULL;
706
707       if (esc1)
708         {
709           for (esc2 = esc1 + 6; *esc2 == ' '; esc2++)
710             ;
711
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);
742         }
743     }
744 }
745
746 void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
747                     char *argv[], char *qual)
748 {
749   char fmt_buf[MR_STMTBUF_LEN];
750   register char *res, *fmt;
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++;
777                         }
778                     }
779                   argv++;
780                   break;
781                 case 'd':
782                   res += sprintf(res, "%d", *(int *)*argv++);
783                   break;
784                 default:                        /* Swallow other %? pairs */
785                   break;
786                 }
787             }
788           else
789             break;
790         }
791       else
792         *res++ = *fmt;                          /* text -> result buffer */
793     }
794   *res = '\0';
795
796   optimize_sql_stmt(result_buf);
797 }
798
799 int do_update(struct query *q, char *argv[], char *qual,
800               int (*action)(), char *actarg)
801 {
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;
807 }
808
809 int do_append(struct query *q, char *argv[], char *pqual,
810               int (*action)(), char *actarg)
811 {
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;
817 }
818
819 int do_delete(struct query *q, char *qual, int (*action)(), char *actarg)
820 {
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;
826 }
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
834  **         limit - should the ID be range limited
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
841 int set_next_object_id(char *object, enum tables table, int limit)
842 {
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;
872         }
873     }
874
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;
879 }
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
886 int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
887 {
888   EXEC SQL BEGIN DECLARE SECTION;
889   int u_id, k_id;
890   char *krbname;
891   EXEC SQL END DECLARE SECTION;
892
893   krbname = name;
894   *kid = 0;
895   *uid = 0;
896
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;
901
902   if (dbms_errno)
903     return mr_errcode;
904
905   if (sqlca.sqlerrd[2] == 1)
906     {
907       *kid = -k_id;
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;
914
915   if (!ok)
916     {
917       *uid = *kid;
918       return MR_SUCCESS;
919     }
920
921   if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
922     *uid = 0;
923
924   if (*kid == 0)
925     *kid = *uid;
926   if (dbms_errno)
927     return mr_errcode;
928   return MR_SUCCESS;
929 }
930
931
932 /* For now this just checks the argc's.  It should also see that there
933  * are no duplicate names.
934  */
935
936 void sanity_check_queries(void)
937 {
938   register int i;
939   int maxv = 0, maxa = 0;
940   extern int QueryCount2;
941   extern struct query Queries2[];
942
943 #define MAX(x, y) ((x) > (y) ? (x) : (y))
944
945   for (i = 0; i < QueryCount2; i++)
946     {
947       maxv = MAX(maxv, Queries2[i].vcnt);
948       maxa = MAX(maxa, Queries2[i].argc);
949     }
950   if (MAX(maxv, maxa) > QMAXARGS)
951     {
952       com_err(whoami, 0, "A query has more args than QMAXARGS");
953       exit(1);
954     }
955 }
956
957
958 /* Generically do a SELECT, storing the results in the provided buffers */
959
960 void dosql(char *buffers[])
961 {
962   int i, errcode = 0, errlen;
963
964   EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
965   if (sqlca.sqlcode)
966     return;
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;
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     }
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 */
982   if (sqlca.sqlcode)
983     {
984       errcode = sqlca.sqlcode;
985       errlen = sqlca.sqlerrm.sqlerrml;
986     }
987
988   EXEC SQL CLOSE inc_crs;
989   if (errcode)
990     {
991       sqlca.sqlcode = errcode;
992       sqlca.sqlerrm.sqlerrml = errlen;
993     }
994 }
995
996 int do_for_all_rows(char *query, int count, int (*action)(), int actarg)
997 {
998   int i, rowcount = 0;
999   EXEC SQL BEGIN DECLARE SECTION;
1000   char *q = query;
1001   EXEC SQL END DECLARE SECTION;
1002
1003   EXEC SQL PREPARE stmt FROM :q;
1004   if (sqlca.sqlcode)
1005     return;
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;
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     }
1026   EXEC SQL CLOSE curs;
1027
1028   if (mr_errcode)
1029     return mr_errcode;
1030   return (rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS;
1031 }
1032
1033
1034 /* eof:qrtn.dc */
This page took 0.124109 seconds and 5 git commands to generate.