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