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