source: trunk/third/moira/server/qrtn.pc @ 24250

Revision 24250, 25.2 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from subversion. Sorry for the large diff - looks like all of the keywords changed in the SVN import process.
Line 
1/* $Id: qrtn.pc,v 2.32 2009-12-29 17:29:33 zacheiss Exp $
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#include <time.h>
20
21EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
22EXEC SQL INCLUDE sqlda;  /* SQL Descriptor Area */
23
24RCSID("$Header: /afs/.athena.mit.edu/astaff/project/moiradev/repository/moira/server/qrtn.pc,v 2.32 2009-12-29 17:29:33 zacheiss Exp $");
25
26SQLDA *mr_sqlda;
27EXEC SQL BEGIN DECLARE SECTION;
28char stmt_buf[MR_STMTBUF_LEN];
29int proxy_acl;
30EXEC SQL END DECLARE SECTION;
31
32char *Argv[QMAXARGS];
33extern char *table_name[];
34extern char *sqlbuffer[QMAXARGS];
35
36int dbms_errno = 0;
37int mr_errcode = 0;
38EXEC SQL BEGIN DECLARE SECTION;
39int query_timeout = 30;
40char *database = "moira";
41EXEC SQL END DECLARE SECTION;
42extern char *whoami;
43extern FILE *journal;
44extern int QueryCount, max_version;
45extern struct query Queries[];
46
47/* Put this in a variable so that we can patch it if necessary */
48int max_row_count = 8192;
49
50int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
51int do_retrieve(struct query *q, char *pqual,
52                int (*action)(int, char *[], void *), void *actarg);
53int do_update(struct query *q, char *argv[], char *qual,
54              int (*action)(int, char *[], void *), void *actarg);
55int do_append(struct query *q, char *argv[], char *pqual,
56              int (*action)(int, char *[], void *), void *actarg);
57int do_delete(struct query *q, char *qual,
58              int (*action)(int, char *[], void *), void *actarg);
59void build_sql_stmt(char *result_buf, char *cmd, char *targetlist,
60                    char *argv[], char *qual);
61
62SQLDA *mr_alloc_sqlda(void);
63void sqlglm(char *, int *, int *);
64
65/*
66 * dbmserr: Called when the DBMS indicates an error.
67 */
68
69void 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(whoami, "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. */
87EXEC SQL WHENEVER SQLERROR DO dbmserr();
88
89int 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 < QMAXARGS; i++)
100        Argv[i] = xmalloc(MAX_FIELD_WIDTH);
101
102      mr_sqlda = mr_alloc_sqlda();
103
104      incremental_init();
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
124void mr_close_database(void)
125{
126  EXEC SQL COMMIT RELEASE;
127}
128
129int mr_check_access(client *cl, char *name, int argc, char *argv_ro[])
130{
131  struct query *q;
132
133  dbms_errno = 0;
134  mr_errcode = 0;
135
136  q = get_query_by_name(name, cl->version);
137  if (!q)
138    return MR_NO_HANDLE;
139
140  return mr_verify_query(cl, q, argc, argv_ro);
141}
142
143int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
144                     int (*action)(int, char *[], void *), void *actarg)
145{
146  struct query *q;
147  int status;
148  struct validate *v;
149  char *qual = NULL;
150  EXEC SQL BEGIN DECLARE SECTION;
151  char *table;
152  EXEC SQL END DECLARE SECTION;
153  struct save_queue *sq;
154
155  dbms_errno = 0;
156  mr_errcode = 0;
157
158  /* list queries command */
159  if (!strcmp(name, "_list_queries"))
160    {
161      list_queries(cl, action, actarg);
162      return MR_SUCCESS;
163    }
164
165  /* help query command */
166  if (!strcmp(name, "_help"))
167    {
168      if (argc < 1)
169        return MR_ARGS;
170      q = get_query_by_name(argv_ro[0], cl->version);
171      if (!q)
172        return MR_NO_HANDLE;
173      help_query(q, action, actarg);
174      return MR_SUCCESS;
175    }
176
177  /* get query structure, return error if named query does not exist */
178  q = get_query_by_name(name, cl->version);
179  if (!q)
180    return MR_NO_HANDLE;
181  v = q->validate;
182
183  /* setup argument vector, verify access and arguments */
184  if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
185    goto out;
186
187  /* perform any special query pre-processing */
188  if (v && v->pre_rtn)
189    {
190      status = (*v->pre_rtn)(q, Argv, cl);
191      if (status != MR_SUCCESS)
192        goto out;
193    }
194
195  switch (q->type)
196    {
197    case MR_Q_RETRIEVE:
198      /* for queries that do not permit wildcarding, check if row
199         uniquely exists */
200      if (v && v->field)
201        {
202          status = validate_row(q, Argv, v);
203          if (status != MR_EXISTS)
204            break;
205        }
206
207      /* build "where" clause if needed */
208      if (q->qual)
209        qual = build_qual(q->qual, q->argc, Argv);
210
211      /* if there is a followup routine, then we must save the results */
212      /* of the first query for use by the followup routine */
213      /* if q->rvar = NULL, perform post_rtn only */
214      if (q->rvar)
215        {
216          if (v && v->post_rtn)
217            {
218              sq = sq_create();
219              status = do_retrieve(q, qual, sq_save_args, sq);
220              if (status != MR_SUCCESS)
221                {
222                  char **argv;
223                  int i;
224
225                  while (sq_get_data(sq, &argv))
226                    {
227                      for (i = 0; i < q->vcnt; i++)
228                        free(argv[i]);
229                      free(argv);
230                    }
231                  sq_destroy(sq);
232                  break;
233                }
234              status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
235            }
236          else
237            {
238              /* normal retrieve */
239              status = do_retrieve(q, qual, action, actarg);
240            }
241          if (status != MR_SUCCESS)
242            break;
243        }
244      else
245        status = (*v->post_rtn)(q, Argv, cl, action, actarg);
246
247      break;
248
249    case MR_Q_UPDATE:
250      /* see if row already exists */
251      if (v->field)
252        {
253          status = validate_row(q, Argv, v);
254          if (status != MR_EXISTS)
255            break;
256        }
257
258      /* build "where" clause and perform update */
259      /* if q->rvar = NULL, perform post_rtn only */
260      if (q->rvar)
261        {
262          qual = build_qual(q->qual, q->argc, Argv);
263          incremental_before(q->rtable, qual, argv_ro);
264          status = do_update(q, &Argv[q->argc], qual, action, actarg);
265          incremental_after(q->rtable, qual, argv_ro);
266          if (status != MR_SUCCESS)
267            break;
268          table = table_name[q->rtable];
269          if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
270            {
271              EXEC SQL UPDATE tblstats
272                SET updates = updates + 1, modtime = SYSDATE
273                WHERE table_name = :table;
274            }
275        }
276
277      /* execute followup routine (if any) */
278      if (v->post_rtn)
279        status = (*v->post_rtn)(q, Argv, cl);
280
281      break;
282
283    case MR_Q_APPEND:
284      /* see if row already exists */
285      if (v->field)
286        {
287          status = validate_row(q, Argv, v);
288          if (status != MR_NO_MATCH)
289            break;
290        }
291
292      /* build "where" clause if needed */
293      if (q->qual)
294        qual = build_qual(q->qual, q->argc, Argv);
295
296      /* perform the append */
297      /* if q->rvar = NULL, perform post_rtn only */
298      if (q->rvar)
299        {
300          incremental_clear_before();
301          status = do_append(q, &Argv[q->argc], qual, action, actarg);
302          if (status != MR_SUCCESS)
303            break;
304          if (v && v->object_id)
305            {
306              qual = realloc(qual, 15 + strlen(q->rvar) +
307                             strlen(Argv[q->argc + q->vcnt]));
308              sprintf(qual, "%s.%s = %s", q->rvar, v->object_id,
309                      Argv[q->argc + q->vcnt]);
310              incremental_after(q->rtable, qual, argv_ro);
311            }
312          else
313            incremental_after(q->rtable, qual, argv_ro);
314
315          table = table_name[q->rtable];
316          EXEC SQL UPDATE tblstats
317            SET appends = appends + 1, modtime = SYSDATE
318            WHERE table_name = :table;
319        }
320
321      /* execute followup routine */
322      if (v->post_rtn)
323        status = (*v->post_rtn)(q, Argv, cl);
324      break;
325
326    case MR_Q_DELETE:
327      /* see if row already exists */
328      if (v->field)
329        {
330          status = validate_row(q, Argv, v);
331          if (status != MR_EXISTS)
332            break;
333        }
334
335      /* build "where" clause and perform delete */
336      /* if q->rvar = NULL, perform post_rtn only */
337      if (q->rvar)
338        {
339          qual = build_qual(q->qual, q->argc, Argv);
340          table = table_name[q->rtable];
341          incremental_before(q->rtable, qual, argv_ro);
342          status = do_delete(q, qual, action, actarg);
343          incremental_clear_after();
344          if (status != MR_SUCCESS)
345            break;
346          EXEC SQL UPDATE tblstats
347            SET deletes = deletes + 1, modtime = SYSDATE
348            WHERE table_name = :table;
349        }
350
351      /* execute followup routine */
352      if (v->post_rtn)
353        status = (*v->post_rtn)(q, Argv, cl);
354      break;
355
356    case MR_Q_SPECIAL:
357      break;
358    }
359
360out:
361  free(qual);
362
363  if (status == MR_SUCCESS && dbms_errno != 0)
364    {
365      com_err(whoami, MR_INTERNAL, "Server didn't notice DBMS ERROR %d",
366              dbms_errno);
367      status = mr_errcode;
368    }
369
370  if (q->type == MR_Q_RETRIEVE)
371    EXEC SQL COMMIT WORK;
372  else
373    {
374      if (status == MR_SUCCESS)
375        {
376          EXEC SQL COMMIT WORK;
377          if (journal)
378            {
379              char *buf;
380              int i;
381              extern time_t now;
382
383              fprintf(journal, "%% %s %s %s",
384                      cl->clname, cl->entity, ctime(&now));
385              fprintf(journal, "%s ", q->name);
386              for (i = 0; i < argc; i++)
387                {
388                  if (i != 0)
389                    putc(' ', journal);
390                  buf = requote(argv_ro[i]);
391                  fputs(buf, journal);
392                  free(buf);
393                }
394              putc('\n', journal);
395              fflush(journal);
396            }
397          incremental_update();
398        }
399      else
400        {
401          EXEC SQL ROLLBACK WORK;
402          incremental_flush();
403        }
404    }
405
406  if (status != MR_SUCCESS)
407    com_err(whoami, status, " (Query failed)");
408  return status;
409}
410
411char *build_qual(char *fmt_buf, int argc, char *argv[])
412{
413  char *res, *result_buf, *fmt, *arg, *like, *p;
414
415  result_buf = xmalloc(2 * (strlen(fmt_buf) + argc * ARGLEN));
416
417  res = result_buf;
418  fmt = fmt_buf;
419
420  like = strstr(fmt, "LIKE");
421  arg = strchr(fmt, '%');
422
423  /* Look through the format for LIKE expressions and arguments.
424     Substitute in the arguments, simplify the `LIKE's to `='s
425     where possible, and insert ESCAPE clauses where needed */
426
427  while (*fmt)
428    {
429     
430      if ((!like && !arg) || argc == 0)
431        {
432          /* only plain text remains */
433          strcpy(res, fmt);
434          res = strchr(res, '\0');
435          break;
436        }
437      else if (!like || arg < like)
438        {
439          /* regular arg: copy up to arg, then substitute */
440          strncpy(res, fmt, arg - fmt);
441          res += arg - fmt;
442          if (*++arg)
443            {
444              switch (*arg++)
445                {
446                case '%':
447                  *res++ = '%';
448                  break;
449
450                case 's':
451                  p = *argv;
452                  /* copy string, doubling single quotes */
453                  while (*p)
454                    {
455                      if (*p == '\'')
456                        *res++ = '\'';
457                      *res++ = *p++;
458                    }
459                  argv++;
460                  break;
461
462                case 'd':
463                  res += sprintf(res, "%d", *(int *)*argv++);
464                  break;
465                }
466            }
467          fmt = arg;
468          arg = strchr(fmt, '%');
469        } else {
470          /* LIKE arg: copy over up to the arg, then copy and convert arg */
471          int escape = 0, pattern = 0;
472          char *likepos = res + (like - fmt);
473
474          strncpy(res, fmt, arg - fmt);
475          res += arg - fmt;
476
477          /* copy arg, converting UNIX globs to `SQL voodoo', and noting
478             if we'll need an ESCAPE clause */
479          for (p = *argv++; *p; p++)
480            {
481              switch (*p)
482                {
483                case '*':
484                  *res++ = '%';
485                  *res++ = '%'; /* need to double for build_sql_stmt */
486                  pattern = 1;
487                  break;
488
489                case '?':
490                  *res++ = '_';
491                  pattern = 1;
492                  break;
493
494                case '%':
495                case '_':
496                  *res++ = '*';
497                  *res++ = *p;
498                  if (*p == '%')
499                    *res++ = *p;
500                  escape = 1;
501                  break;
502
503                case '\'':
504                  *res++ = '\'';
505                  /* fall through */
506
507                default:
508                  *res++ = *p;
509                }
510            }
511
512          /* if no pattern characters, write over "LIKE" with " =  " */
513          if (!pattern && !escape)
514            memcpy(likepos, " =  ", 4);
515
516          fmt = arg + 2;
517          while (*fmt && *fmt != ' ')
518            *res++ = *fmt++;
519
520          if (escape)
521            res += sprintf(res, " ESCAPE '*'");
522
523          arg = strchr(fmt, '%');
524          like = strstr(fmt, "LIKE");
525        }
526    }
527
528  *res = '\0';
529  result_buf = realloc(result_buf, strlen(result_buf) + 1);
530  return result_buf;
531}
532
533/* Build arguement vector, verify query and arguments */
534
535int privileged;
536
537int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
538{
539  int argreq;
540  int status;
541  struct validate *v = q->validate;
542  int i;
543  char *to, *fr, *stop;
544
545  privileged = 0;
546
547  /* check argument count */
548  argreq = q->argc;
549  if (q->type == MR_Q_UPDATE || q->type == MR_Q_APPEND)
550    argreq += q->vcnt;
551  if (argc != argreq)
552    return MR_ARGS;
553
554  /* copy the arguments into a local argv that we can modify */
555  for (i = 0; i < argc; i++)
556    {
557      for (to = Argv[i], fr = argv_ro[i], stop = to + MAX_FIELD_WIDTH; (*fr) && (to < stop);)
558        *to++ = *fr++;
559
560      if (*fr)
561        return MR_ARG_TOO_LONG;
562      *to = '\0';
563    }
564
565  /* Check initial query access.  If we're acting as a proxy, only allow
566   * access if the query has "default" as a capacl.
567   */
568  status = check_query_access(q, Argv, cl);
569  if (status != MR_SUCCESS && status != MR_PERM)
570    return status;
571  if (status == MR_SUCCESS && (!cl->proxy_id || q->everybody))
572      privileged++;
573
574  /* validate arguments */
575  if (v && v->valobj)
576    {
577      status = validate_fields(q, Argv, v->valobj, v->objcnt);
578      if (status != MR_SUCCESS)
579        return status;
580    }
581
582  /* perform special query access check */
583  if (!privileged && v && v->acs_rtn)
584    {
585      status = (*v->acs_rtn)(q, Argv, cl);
586      if (status != MR_SUCCESS && status != MR_PERM)
587        return status;
588      if (status == MR_SUCCESS)
589        return MR_SUCCESS;
590    }
591
592  return privileged ? MR_SUCCESS : MR_PERM;
593}
594
595int check_query_access(struct query *q, char *argv[], client *cl)
596{
597  EXEC SQL BEGIN DECLARE SECTION;
598  char *name;
599  int acl_id;
600  static int def_uid;
601  EXEC SQL END DECLARE SECTION;
602
603  /* initialize default uid */
604  if (def_uid == 0)
605    EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
606
607  name = q->shortname;
608  EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
609  if (sqlca.sqlcode < 0)
610    return MR_DBMS_ERR;
611  if (sqlca.sqlcode == SQL_NO_MATCH)
612    return MR_PERM;
613  q->acl = acl_id;
614 
615  /* check for default access */
616  EXEC SQL SELECT member_id INTO :acl_id FROM imembers
617    WHERE list_id = :acl_id AND member_type = 'USER'
618    AND member_id = :def_uid;
619  if (sqlca.sqlerrd[2] == 0)
620    q->everybody = 0;
621  else
622    q->everybody = 1;
623
624  if (q->everybody)
625    return MR_SUCCESS;
626
627  if (find_member("LIST", acl_id, cl))
628    return MR_SUCCESS;
629  else
630    return MR_PERM;
631}
632
633int find_member(char *list_type, int list_id, client *cl)
634{
635  EXEC SQL BEGIN DECLARE SECTION;
636  int flag, users_id, client_id;
637  EXEC SQL END DECLARE SECTION;
638
639  if (!strcmp(strtrim(list_type), "USER") && list_id == cl->users_id)
640    return 1;
641
642  if (!strcmp(strtrim(list_type), "KERBEROS") && list_id == -cl->client_id)
643    return 1;
644
645  if (!strcmp(strtrim(list_type), "LIST"))
646    {
647      /* see if client is a member of list */
648      flag = 0;
649      users_id = cl->users_id;
650      client_id = -cl->client_id;
651      EXEC SQL SELECT COUNT(member_id) INTO :flag FROM imembers
652        WHERE list_id = :list_id
653        AND ( ( member_type = 'USER' AND member_id = :users_id )
654              OR (member_type = 'KERBEROS' AND member_id = :client_id ) );
655      if (sqlca.sqlcode == 0)
656        return flag;
657    }
658
659  return 0;
660}
661
662
663int 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
676void 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
727int 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
737int 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
747int 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 MR_Q_APPEND operation to set the next object id to
766 **   be used for the new record to the next free value
767 **
768 **/
769
770int 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#ifdef ULTRIX_ID_HOLE
786      if (limit && value > 31999 && value < 32768)
787        value = 32768;
788#endif
789      if (limit && value > MAX_ID_VALUE)
790        value = MIN_ID_VALUE;
791
792      sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = %d",
793              object, table_name[table], object, value);
794      dosql(sqlbuffer);
795      if (sqlca.sqlcode < 0)
796        return mr_errcode;
797      if (sqlca.sqlcode == SQL_NO_MATCH)
798        break;
799
800      value++;
801      if (limit && value == starting_value)
802        {
803          com_err(whoami, 0, "All id values have been used");
804          return MR_NO_ID;
805        }
806    }
807
808  com_err(whoami, 0, "setting ID %s to %d", object, value);
809  EXEC SQL UPDATE numvalues SET value = :value WHERE name = :obj;
810  return MR_SUCCESS;
811}
812
813
814/* Turn a kerberos name into the user's ID of the account that principal
815 * owns.  Sets the kerberos ID and user ID.
816 */
817
818int set_krb_mapping(char *name, char *login, int ok, int *kid, int *uid)
819{
820  EXEC SQL BEGIN DECLARE SECTION;
821  int u_id, k_id;
822  char *krbname;
823  EXEC SQL END DECLARE SECTION;
824
825  krbname = name;
826  *kid = 0;
827  *uid = 0;
828
829  EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
830    FROM krbmap km, strings str
831    WHERE km.string_id = str.string_id AND str.string = :krbname;
832  EXEC SQL COMMIT WORK;
833
834  if (dbms_errno)
835    return mr_errcode;
836
837  if (sqlca.sqlerrd[2] == 1)
838    {
839      *kid = -k_id;
840      *uid = u_id;
841      return MR_SUCCESS;
842    }
843
844  if (name_to_id(name, STRINGS_TABLE, &k_id) == MR_SUCCESS)
845    *kid = -k_id;
846
847  if (!ok)
848    {
849      *uid = *kid;
850      return MR_SUCCESS;
851    }
852
853  if (name_to_id(login, USERS_TABLE, uid) != MR_SUCCESS)
854    *uid = 0;
855
856  if (*kid == 0)
857    *kid = *uid;
858  if (dbms_errno)
859    return mr_errcode;
860  return MR_SUCCESS;
861}
862
863
864void sanity_check_queries(void)
865{
866  int i;
867  int maxv = 0, maxa = 0;
868
869#define MAX(x, y) ((x) > (y) ? (x) : (y))
870
871  for (i = 0; i < QueryCount; i++)
872    {
873      maxv = MAX(maxv, Queries[i].vcnt);
874      maxa = MAX(maxa, Queries[i].argc);
875      max_version = MAX(max_version, Queries[i].version);
876    }
877  if (MAX(maxv, maxa) > QMAXARGS)
878    {
879      com_err(whoami, 0, "A query has more args than QMAXARGS");
880      exit(1);
881    }
882}
883
884
885/* Generically do a SELECT, storing the results in the provided buffers */
886
887void dosql(char *buffers[])
888{
889  int i, errcode = 0, errlen;
890
891  EXEC SQL PREPARE inc_stmt FROM :stmt_buf;
892  if (sqlca.sqlcode)
893    return;
894  EXEC SQL DECLARE inc_crs CURSOR FOR inc_stmt;
895  EXEC SQL OPEN inc_crs;
896  mr_sqlda->N = QMAXARGS;
897  EXEC SQL DESCRIBE SELECT LIST FOR inc_stmt INTO mr_sqlda;
898  mr_sqlda->N = mr_sqlda->F;
899  for (i = 0; i < mr_sqlda->N; i++)
900    {
901      mr_sqlda->V[i] = buffers[i];
902      mr_sqlda->T[i] = 97;
903      mr_sqlda->L[i] = MAX_FIELD_WIDTH;
904    }
905  EXEC SQL FETCH inc_crs USING DESCRIPTOR mr_sqlda;
906
907  /* if we got an error from the FETCH, we have to preserve it or the
908     close will reset it and the caller will think nothing happened */
909  if (sqlca.sqlcode)
910    {
911      errcode = sqlca.sqlcode;
912      errlen = sqlca.sqlerrm.sqlerrml;
913    }
914
915  EXEC SQL CLOSE inc_crs;
916  if (errcode)
917    {
918      sqlca.sqlcode = errcode;
919      sqlca.sqlerrm.sqlerrml = errlen;
920    }
921}
922
923int do_for_all_rows(char *query, int count,
924                    int (*action)(int, char *[], void *), void *actarg)
925{
926  int i, rowcount = 0;
927  EXEC SQL BEGIN DECLARE SECTION;
928  char *q = query;
929  EXEC SQL END DECLARE SECTION;
930
931  EXEC SQL PREPARE stmt FROM :q;
932  if (sqlca.sqlcode)
933    return MR_INTERNAL;
934  EXEC SQL DECLARE curs CURSOR FOR stmt;
935  EXEC SQL OPEN curs;
936  mr_sqlda->N = count;
937  EXEC SQL DESCRIBE SELECT LIST FOR stmt INTO mr_sqlda;
938  mr_sqlda->N = mr_sqlda->F;
939  for (i = 0; i < mr_sqlda->N; i++)
940    {
941      mr_sqlda->V[i] = sqlbuffer[i];
942      mr_sqlda->T[i] = 97;
943      mr_sqlda->L[i] = MAX_FIELD_WIDTH;
944    }
945
946  while (rowcount < max_row_count)
947    {
948      EXEC SQL FETCH curs USING DESCRIPTOR mr_sqlda;
949      if (sqlca.sqlcode)
950        break;
951      (*action)(count, sqlbuffer, actarg);
952      rowcount++;
953    }
954  EXEC SQL CLOSE curs;
955
956  if (mr_errcode)
957    return mr_errcode;
958  if (rowcount == max_row_count)
959    {
960      critical_alert(whoami, "moirad", "attempted query with too many rows");
961      return MR_NO_MEM;
962    }
963  else if (rowcount == 0)
964    return MR_NO_MATCH;
965  else
966    return MR_SUCCESS;
967}
968
969/* Do a name to ID translation.  Moved from cache.pc because we did away
970 * with the cache, but what this function does is still useful to us.
971 */
972
973int name_to_id(char *name, enum tables type, int *id)
974{
975  EXEC SQL BEGIN DECLARE SECTION;
976  char *iname;
977  int j;
978  EXEC SQL END DECLARE SECTION;
979
980  iname = name;
981
982  switch (type)
983    {
984    case USERS_TABLE:
985      if (strchr(iname, '@') || (strlen(iname) > 8))
986        {
987          sqlca.sqlcode = SQL_NO_MATCH;
988          break;
989        }
990      EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
991      break;
992    case LIST_TABLE:
993      EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
994      break;
995    case MACHINE_TABLE:
996      EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
997      break;
998    case SUBNET_TABLE:
999      EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
1000      break;
1001    case CLUSTERS_TABLE:
1002      EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
1003      break;
1004    case FILESYS_TABLE:
1005      EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
1006      break;
1007    case STRINGS_TABLE:
1008      if (!iname[0])    /* special-case empty string */
1009        {
1010          *id = 0;
1011          return MR_SUCCESS;
1012        }
1013      EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
1014      break;
1015    case CONTAINERS_TABLE:
1016      EXEC SQL SELECT cnt_id INTO :j FROM containers WHERE LOWER(name) =
1017        LOWER(:iname);
1018      break;
1019    default:
1020      return MR_INTERNAL;
1021    }
1022  if (sqlca.sqlcode == SQL_NO_MATCH)
1023    return MR_NO_MATCH;
1024  if (sqlca.sqlerrd[2] > 1)
1025    return MR_NOT_UNIQUE;
1026  if (sqlca.sqlcode)
1027    return MR_DBMS_ERR;
1028  *id = j;
1029
1030  return MR_SUCCESS;
1031}
1032
1033/* Perform an ID to name mapping.  name should be a pointer to a pointer to
1034 * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
1035 * allocated with the answer.
1036 *
1037 * This used to be in cache.pc, but we've removed the cache, and this function
1038 * is still useful to us.
1039 */
1040
1041int id_to_name(int id, enum tables type, char **name)
1042{
1043  EXEC SQL BEGIN DECLARE SECTION;
1044  char iname[MAX_FIELD_WIDTH];
1045  int j;
1046  EXEC SQL END DECLARE SECTION;
1047
1048  j = id;
1049
1050  switch (type)
1051    {
1052    case USERS_TABLE:
1053      EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
1054      break;
1055    case LIST_TABLE:
1056      EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
1057      break;
1058    case MACHINE_TABLE:
1059      EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
1060      break;
1061    case SUBNET_TABLE:
1062      EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
1063      break;
1064    case CLUSTERS_TABLE:
1065      EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
1066      break;
1067    case FILESYS_TABLE:
1068      EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
1069      break;
1070    case STRINGS_TABLE:
1071      EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
1072      break;
1073    case CONTAINERS_TABLE:
1074      EXEC SQL SELECT name INTO :iname FROM containers WHERE cnt_id = :j;
1075      break;
1076    default:
1077      return MR_INTERNAL;
1078    }
1079  if (sqlca.sqlcode == SQL_NO_MATCH)
1080    {
1081      free(*name);
1082      sprintf(iname, "#%d", j);
1083      *name = xstrdup(iname);
1084      return MR_NO_MATCH;
1085    }
1086  if (sqlca.sqlerrd[2] > 1)
1087    return MR_INTERNAL;
1088  if (sqlca.sqlcode)
1089    return MR_DBMS_ERR;
1090  free(*name);
1091  *name = xstrdup(strtrim(iname));
1092
1093  return MR_SUCCESS;
1094}
1095
1096/* eof:qrtn.dc */
Note: See TracBrowser for help on using the repository browser.