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