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