]> andersk Git - moira.git/blob - server/qrtn.pc
Move conversion of UNIX->SQL wildcards from query validation stage to
[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;
463
464           strncpy(res, fmt, arg - fmt);
465           res += arg - fmt;
466
467           /* copy arg, converting UNIX globs to `SQL voodoo', and noting
468              if we'll need an ESCAPE clause */
469           for (p = *argv++; *p; p++)
470             {
471               switch (*p)
472                 {
473                 case '*':
474                   *res++ = '%';
475                   *res++ = '%'; /* need to double for build_sql_stmt */
476                   break;
477
478                 case '?':
479                   *res++ = '_';
480                   break;
481
482                 case '%':
483                 case '_':
484                   *res++ = '*';
485                   *res++ = *p;
486                   if (*p == '%')
487                     *res++ = *p;
488                   escape = 1;
489                   break;
490
491                 case '\'':
492                   *res++ = '\'';
493                   /* fall through */
494
495                 default:
496                   *res++ = *p;
497                 }
498             }
499
500           fmt = arg + 2;
501           if (*fmt == '\'')
502             *res++ = *fmt++;
503
504           if (escape)
505             res += sprintf(res, " ESCAPE '*'");
506
507           arg = strchr(fmt, '%');
508           like = strstr(fmt, "LIKE");
509         }
510     }
511
512   *res = '\0';
513   result_buf = realloc(result_buf, strlen(result_buf) + 1);
514   return result_buf;
515 }
516
517 /* Build arguement vector, verify query and arguments */
518
519 int privileged;
520
521 int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
522 {
523   int argreq;
524   int status;
525   struct validate *v = q->validate;
526   int i;
527   char *to, *fr, *stop;
528
529   privileged = 0;
530
531   /* check argument count */
532   argreq = q->argc;
533   if (q->type == UPDATE || q->type == APPEND)
534     argreq += q->vcnt;
535   if (argc != argreq)
536     return MR_ARGS;
537
538   /* copy the arguments into a local argv that we can modify */
539   for (i = 0; i < argc; i++)
540     {
541       for (to = Argv[i], fr = argv_ro[i], stop = to + MAX_FIELD_WIDTH; (*fr) && (to < stop);)
542         *to++ = *fr++;
543
544       if (*fr)
545         return MR_ARG_TOO_LONG;
546       *to = '\0';
547
548       if (to > Argv[i] && *--to == '\\')
549         return MR_BAD_CHAR;
550     }
551
552   /* check initial query access */
553   status = check_query_access(q, Argv, cl);
554   if (status != MR_SUCCESS && status != MR_PERM)
555     return status;
556   if (status == MR_SUCCESS)
557     privileged++;
558
559   /* validate arguments */
560   if (v && v->valobj)
561     {
562       status = validate_fields(q, Argv, v->valobj, v->objcnt);
563       if (status != MR_SUCCESS)
564         return status;
565     }
566
567   /* perform special query access check */
568   if (!privileged && v && v->acs_rtn)
569     {
570       status = (*v->acs_rtn)(q, Argv, cl);
571       if (status != MR_SUCCESS && status != MR_PERM)
572         return status;
573       if (status == MR_SUCCESS)
574         return MR_SUCCESS;
575     }
576
577   return privileged ? MR_SUCCESS : MR_PERM;
578 }
579
580
581 /* This routine caches info from the database.  Each query acl is stored
582  * in the query structure, and whether that acl contains everybody.
583  */
584
585 int check_query_access(struct query *q, char *argv[], client *cl)
586 {
587   EXEC SQL BEGIN DECLARE SECTION;
588   char *name;
589   int acl_id;
590   static int def_uid;
591   EXEC SQL END DECLARE SECTION;
592
593   /* initialize default uid */
594   if (def_uid == 0)
595     EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
596
597   /* get query access control list */
598   if (q->acl != 0)
599     acl_id = q->acl;
600   else
601     {
602       name = q->shortname;
603       EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
604       if (sqlca.sqlcode < 0)
605         return MR_DBMS_ERR;
606       if (sqlca.sqlcode == SQL_NO_MATCH)
607         return MR_PERM;
608       q->acl = acl_id;
609
610       /* check for default access */
611       EXEC SQL SELECT member_id INTO :acl_id FROM imembers
612         WHERE list_id = :acl_id AND member_type = 'USER'
613         AND member_id = :def_uid;
614       if (sqlca.sqlerrd[2] == 0)
615         q->everybody = 0;
616       else
617         q->everybody = 1;
618     }
619
620   if (q->everybody)
621     return MR_SUCCESS;
622
623   if (find_member("LIST", acl_id, cl))
624     return MR_SUCCESS;
625   else
626     return MR_PERM;
627 }
628
629
630 int find_member(char *list_type, int list_id, client *cl)
631 {
632   EXEC SQL BEGIN DECLARE SECTION;
633   int flag, users_id, client_id;
634   EXEC SQL END DECLARE SECTION;
635
636   if (!strcmp(strtrim(list_type), "USER") && list_id == cl->users_id)
637     return 1;
638
639   if (!strcmp(strtrim(list_type), "KERBEROS") && list_id == -cl->client_id)
640     return 1;
641
642   /* see if client is a member of list */
643   flag = 0;
644   users_id = cl->users_id;
645   client_id = -cl->client_id;
646   EXEC SQL SELECT COUNT(member_id) INTO :flag FROM imembers
647     WHERE list_id = :list_id
648     AND ( ( member_type = 'USER' AND member_id = :users_id )
649           OR (member_type = 'KERBEROS' AND member_id = :client_id ) );
650   if (sqlca.sqlcode == 0)
651     return flag;
652   return 0;
653 }
654
655
656 int do_retrieve(struct query *q, char *pqual,
657                 int (*action)(int, char *[], void *), void *actarg)
658 {
659   build_sql_stmt(stmt_buf, "SELECT", q->tlist, NULL, pqual);
660   if (q->sort)
661     {
662       strcat(stmt_buf, " ORDER BY ");
663       strcat(stmt_buf, q->sort);
664     }
665
666   return do_for_all_rows(stmt_buf, q->vcnt, action, actarg);
667 }
668
669 void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
670                     char *argv[], char *qual)
671 {
672   char fmt_buf[MR_STMTBUF_LEN];
673   char *res, *fmt;
674
675   if (qual)
676     sprintf(fmt_buf, "%s %s WHERE %s", cmd, targetlist, qual);
677   else
678     sprintf(fmt_buf, "%s %s", cmd, targetlist);
679
680   for (res = result_buf, fmt = fmt_buf; *fmt; fmt++)
681     {
682       if (*fmt == '%')
683         {
684           if (*++fmt)
685             {
686               switch (*fmt)
687                 {
688                 case '%':                       /* %% -> % */
689                   *res++ = *fmt;
690                   break;
691                 case 's':
692                   if (*argv[0])
693                     {
694                       char *p = *argv;
695                       while (*p)
696                         {
697                           if (*p == '\'')
698                             *res++ = '\'';      /* double the ' */
699                           *res++ = *p++;
700                         }
701                     }
702                   argv++;
703                   break;
704                 case 'd':
705                   res += sprintf(res, "%d", *(int *)*argv++);
706                   break;
707                 default:                        /* Swallow other %? pairs */
708                   break;
709                 }
710             }
711           else
712             break;
713         }
714       else
715         *res++ = *fmt;                          /* text -> result buffer */
716     }
717   *res = '\0';
718 }
719
720 int do_update(struct query *q, char *argv[], char *qual,
721               int (*action)(int, char *[], void *), void *actarg)
722 {
723   build_sql_stmt(stmt_buf, "UPDATE", q->tlist, argv, qual);
724   EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
725   if (mr_errcode)
726     return mr_errcode;
727   return MR_SUCCESS;
728 }
729
730 int do_append(struct query *q, char *argv[], char *pqual,
731               int (*action)(int, char *[], void *), void *actarg)
732 {
733   build_sql_stmt(stmt_buf, "INSERT", q->tlist, argv, pqual);
734   EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
735   if (mr_errcode)
736     return mr_errcode;
737   return MR_SUCCESS;
738 }
739
740 int do_delete(struct query *q, char *qual,
741               int (*action)(int, char *[], void *), void *actarg)
742 {
743   sprintf(stmt_buf, "DELETE FROM %s WHERE %s", table_name[q->rtable], qual);
744   EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
745   if (mr_errcode)
746     return mr_errcode;
747   return MR_SUCCESS;
748 }
749
750
751 /**
752  ** set_next_object_id - set next object id in values table
753  **
754  ** Inputs: object - object name in values table and in objects
755  **         table - name of table objects are found in
756  **         limit - should the ID be range limited
757  **
758  ** - called before an APPEND operation to set the next object id to
759  **   be used for the new record to the next free value
760  **
761  **/
762
763 int set_next_object_id(char *object, enum tables table, int limit)
764 {
765   EXEC SQL BEGIN DECLARE SECTION;
766   int value;
767   char *obj = object;
768   EXEC SQL END DECLARE SECTION;
769   int starting_value;
770
771   EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :obj;
772   if (sqlca.sqlerrd[2] != 1)
773     return MR_NO_ID;
774
775   starting_value = value;
776   while (1)
777     {
778       if (limit && value > MAX_ID_VALUE)
779         value = MIN_ID_VALUE;
780
781       sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = %d",
782               object, table_name[table], object, value);
783       dosql(sqlbuffer);
784       if (sqlca.sqlcode < 0)
785         return mr_errcode;
786       if (sqlca.sqlcode == SQL_NO_MATCH)
787         break;
788
789       value++;
790       if (limit && value == starting_value)
791         {
792           com_err(whoami, 0, "All id values have been used");
793           return MR_NO_ID;
794         }
795     }
796
797   com_err(whoami, 0, "setting ID %s to %d", object, value);
798   EXEC SQL UPDATE numvalues SET value = :value WHERE name = :obj;
799   return MR_SUCCESS;
800 }
801
802
803 /* Turn a kerberos name into the user's ID of the account that principal
804  * owns.  Sets the kerberos ID and user ID.
805  */
806
807 int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
808 {
809   EXEC SQL BEGIN DECLARE SECTION;
810   int u_id, k_id;
811   char *krbname;
812   EXEC SQL END DECLARE SECTION;
813
814   krbname = name;
815   *kid = 0;
816   *uid = 0;
817
818   EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
819     FROM krbmap km, strings str
820     WHERE km.string_id = str.string_id AND str.string = :krbname;
821   EXEC SQL COMMIT WORK;
822
823   if (dbms_errno)
824     return mr_errcode;
825
826   if (sqlca.sqlerrd[2] == 1)
827     {
828       *kid = -k_id;
829       *uid = u_id;
830       return MR_SUCCESS;
831     }
832
833   if (name_to_id(name, STRINGS_TABLE, &k_id) == MR_SUCCESS)
834     *kid = -k_id;
835
836   if (!ok)
837     {
838       *uid = *kid;
839       return MR_SUCCESS;
840     }
841
842   if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
843     *uid = 0;
844
845   if (*kid == 0)
846     *kid = *uid;
847   if (dbms_errno)
848     return mr_errcode;
849   return MR_SUCCESS;
850 }
851
852
853 /* For now this just checks the argc's.  It should also see that there
854  * are no duplicate names.
855  */
856
857 void sanity_check_queries(void)
858 {
859   int i;
860   int maxv = 0, maxa = 0;
861   extern int QueryCount2;
862   extern struct query Queries2[];
863
864 #define MAX(x, y) ((x) > (y) ? (x) : (y))
865
866   for (i = 0; i < QueryCount2; i++)
867     {
868       maxv = MAX(maxv, Queries2[i].vcnt);
869       maxa = MAX(maxa, Queries2[i].argc);
870     }
871   if (MAX(maxv, maxa) > QMAXARGS)
872     {
873       com_err(whoami, 0, "A query has more args than QMAXARGS");
874       exit(1);
875     }
876 }
877
878
879 /* Generically do a SELECT, storing the results in the provided buffers */
880
881 void dosql(char *buffers[])
882 {
883   int i, errcode = 0, errlen;
884
885   EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
886   if (sqlca.sqlcode)
887     return;
888   EXEC SQL DECLARE inc_crs CURSOR FOR inc_stmt;
889   EXEC SQL OPEN inc_crs;
890   mr_sqlda->N = QMAXARGS;
891   EXEC SQL DESCRIBE SELECT LIST FOR inc_stmt INTO mr_sqlda;
892   mr_sqlda->N = mr_sqlda->F;
893   for (i = 0; i < mr_sqlda->N; i++)
894     {
895       mr_sqlda->V[i] = buffers[i];
896       mr_sqlda->T[i] = 97;
897       mr_sqlda->L[i] = MAX_FIELD_WIDTH;
898     }
899   EXEC SQL FETCH inc_crs USING DESCRIPTOR mr_sqlda;
900
901   /* if we got an error from the FETCH, we have to preserve it or the
902      close will reset it and the caller will think nothing happened */
903   if (sqlca.sqlcode)
904     {
905       errcode = sqlca.sqlcode;
906       errlen = sqlca.sqlerrm.sqlerrml;
907     }
908
909   EXEC SQL CLOSE inc_crs;
910   if (errcode)
911     {
912       sqlca.sqlcode = errcode;
913       sqlca.sqlerrm.sqlerrml = errlen;
914     }
915 }
916
917 int do_for_all_rows(char *query, int count,
918                     int (*action)(int, char *[], void *), void *actarg)
919 {
920   int i, rowcount = 0;
921   EXEC SQL BEGIN DECLARE SECTION;
922   char *q = query;
923   EXEC SQL END DECLARE SECTION;
924
925   EXEC SQL PREPARE stmt FROM :q;
926   if (sqlca.sqlcode)
927     return MR_INTERNAL;
928   EXEC SQL DECLARE curs CURSOR FOR stmt;
929   EXEC SQL OPEN curs;
930   mr_sqlda->N = count;
931   EXEC SQL DESCRIBE SELECT LIST FOR stmt INTO mr_sqlda;
932   mr_sqlda->N = mr_sqlda->F;
933   for (i = 0; i < mr_sqlda->N; i++)
934     {
935       mr_sqlda->V[i] = sqlbuffer[i];
936       mr_sqlda->T[i] = 97;
937       mr_sqlda->L[i] = MAX_FIELD_WIDTH;
938     }
939
940   while (1)
941     {
942       EXEC SQL FETCH curs USING DESCRIPTOR mr_sqlda;
943       if (sqlca.sqlcode)
944         break;
945       (*action)(count, sqlbuffer, actarg);
946       rowcount++;
947     }
948   EXEC SQL CLOSE curs;
949
950   if (mr_errcode)
951     return mr_errcode;
952   return (rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS;
953 }
954
955
956 /* eof:qrtn.dc */
This page took 0.119335 seconds and 5 git commands to generate.