]> andersk Git - moira.git/blob - server/qrtn.dc
make privileged (in access check) a global
[moira.git] / server / qrtn.dc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  * 
10  */
11
12 #ifndef lint
13 static char *rcsid_qrtn_dc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include <string.h>
18 #include "query.h"
19 #include "mr_server.h"
20 EXEC SQL INCLUDE sqlca;  /* SQL Communications Area */
21 EXEC SQL INCLUDE sqlda;  /* SQL Descriptor Area */
22 #include "qrtn.h"
23
24 MR_SQLDA_T *SQLDA;
25 EXEC SQL BEGIN DECLARE SECTION; 
26 int mr_sig_length;
27 int idummy;                            
28 char cdummy[MR_CDUMMY_LEN];            
29 char stmt_buf[MR_STMTBUF_LEN];
30 EXEC SQL END DECLARE SECTION; 
31
32 char *Argv[QMAXARGS];
33
34 int ingres_errno = 0;
35 int mr_errcode = 0;
36 EXEC SQL BEGIN DECLARE SECTION; 
37 int query_timeout = 30;
38 char *database = "moira";
39 EXEC SQL END DECLARE SECTION;
40 extern char *whoami;
41 extern FILE *journal;
42
43 #define INGRES_BAD_DATE1  40206
44 #define INGRES_BAD_DATE2  40207
45 #define INGRES_DEADLOCK   49900
46 #define INGRES_TIMEOUT    39100
47 #define INGRES_BAD_COLUMN 30110
48 #define INGRES_ASGN_ERR   40204
49 #define INGRES_NO_CURSOR  30120
50 #define INGRES_NO_STMT    30130
51
52 /*
53  * ingerr: Called when Ingres indicates an error.
54  */
55
56 void ingerr()
57 {
58     EXEC SQL BEGIN DECLARE SECTION; 
59     char err_msg[256];
60     EXEC SQL END DECLARE SECTION;
61     ingres_errno = -sqlca.sqlcode;
62
63     switch (ingres_errno) {
64       case INGRES_BAD_DATE1:
65       case INGRES_BAD_DATE2:
66         mr_errcode = MR_DATE;
67         break;
68       case INGRES_DEADLOCK:
69         mr_errcode = MR_DEADLOCK;
70         com_err(whoami, 0, "INGRES deadlock detected");
71         break;
72       case INGRES_TIMEOUT:
73 /* May be something other than timeout! #39100 is "Unknown error" 
74  * Really should parse the error message enough to decide if it's a timeout */
75         mr_errcode = MR_BUSY;
76         com_err(whoami, 0, "timed out getting lock");
77         break;
78 /* These should never come up unless someone breaks the query table */
79       case INGRES_NO_CURSOR:
80         if (mr_errcode != MR_BUSY &&
81             mr_errcode != MR_DEADLOCK)
82           mr_errcode = MR_INTERNAL;
83         com_err(whoami, 0, "Cursor not opened");
84         break;
85       case INGRES_NO_STMT:
86         mr_errcode = MR_INTERNAL;
87         com_err(whoami, 0, "Statement not declared");
88         break;
89       case INGRES_BAD_COLUMN:
90         mr_errcode = MR_INTERNAL;
91         com_err(whoami, 0, "Bad column name in query table");
92         break;
93       case INGRES_ASGN_ERR:
94         mr_errcode = MR_INTERNAL;
95         com_err(whoami, 0, "Error in SQL assignment statement");
96         break;
97 /* Others ??? */
98       default:
99         mr_errcode = MR_INGRES_ERR;
100         com_err(whoami, MR_INGRES_ERR, " code %d\n", ingres_errno);
101         EXEC SQL INQUIRE_SQL(:err_msg = errortext);
102         com_err(whoami, 0, "SQL error text = %s", err_msg);
103         critical_alert("MOIRA", "Moira server encountered INGRES ERROR %d", ingres_errno);
104     }
105 }
106
107 /* This is declarative, not executed.  Applies from here on, in this file. */
108 EXEC SQL WHENEVER SQLERROR CALL ingerr;
109
110 int mr_open_database()
111 {
112     register int i;
113     char *malloc();
114     MR_SQLDA_T *mr_alloc_SQLDA();
115     static first_open = 1;
116
117     if (first_open) {
118         first_open = 0;
119
120         /* initialize local argv */
121         for (i = 0; i < 16; i++)
122           Argv[i] = malloc(ARGLEN);
123
124         SQLDA = mr_alloc_SQLDA();       
125
126         incremental_init();
127         flush_cache();
128     }
129         
130     ingres_errno = 0;
131     mr_errcode = 0;
132
133     /* open the database */
134 #ifsql INGRES
135     EXEC SQL CONNECT :database;
136     if(ingres_errno) 
137       return (ingres_errno);
138     EXEC SQL set lockmode session where level = table, timeout = :query_timeout;
139     EXEC SQL set lockmode on capacls where readlock = shared;
140     EXEC SQL set lockmode on alias where readlock = shared;
141 #endsql
142 #ifsql INFORMIX
143     EXEC SQL DATABASE moira
144 #endsql
145
146     if(ingres_errno) 
147         return(mr_errcode);
148
149     EXEC SQL SELECT SIZE(signature) INTO :mr_sig_length FROM users WHERE users_id=0; /* Harmless on second open */
150     EXEC SQL COMMIT WORK;
151     if(ingres_errno)
152         return(mr_errcode);
153
154     return(MR_SUCCESS);
155 }
156
157 int mr_close_database()
158 {
159     flush_cache();
160 #ifsql INGRES
161     EXEC SQL DISCONNECT;
162 #endsql
163 }
164
165 mr_check_access(cl, name, argc, argv_ro)
166     client *cl;
167     char *name;
168     int argc;
169     char *argv_ro[];
170 {
171     struct query *q;
172     struct query *get_query_by_name();
173
174     ingres_errno = 0;
175     mr_errcode = 0;
176
177     q = get_query_by_name(name, cl->args->mr_version_no);
178     if (q == (struct query *)0)
179         return(MR_NO_HANDLE);
180
181     return(mr_verify_query(cl, q, argc, argv_ro));    
182 }
183
184 mr_process_query(cl, name, argc, argv_ro, action, actarg)
185     client *cl;
186     char *name;
187     int argc;
188     char *argv_ro[];
189     int (*action)();
190     char *actarg;
191 {
192     register struct query *q;
193     register int status;
194     register struct validate *v;
195     char qual[256];
196     char sort[32];
197     char *pqual;
198     char *psort;
199     EXEC SQL BEGIN DECLARE SECTION; 
200     char *table_name;
201     EXEC SQL END DECLARE SECTION; 
202     struct save_queue *sq;
203     struct query *get_query_by_name();
204     int sq_save_args();
205     struct save_queue *sq_create();
206     char *build_sort();
207
208     ingres_errno = 0;
209     mr_errcode = 0;
210
211     /* list queries command */
212     if (!strcmp(name, "_list_queries")) {
213         list_queries(cl->args->mr_version_no, action, actarg);
214         return(MR_SUCCESS);
215     }
216
217     /* help query command */
218     if (!strcmp(name, "_help")) {
219         if (argc < 1)
220             return(MR_ARGS);
221         q = get_query_by_name(argv_ro[0], cl->args->mr_version_no);
222         if (q == (struct query *)0) return(MR_NO_HANDLE);
223         help_query(q, action, actarg);
224         return(MR_SUCCESS);
225     }
226
227     /* get query structure, return error if named query does not exist */
228     q = get_query_by_name(name, cl->args->mr_version_no);
229     if (q == (struct query *)0) return(MR_NO_HANDLE);
230     v = q->validate;
231
232     /* setup argument vector, verify access and arguments */
233     if ((status = mr_verify_query(cl, q, argc, argv_ro)) != MR_SUCCESS)
234         goto out;
235
236     /* perform any special query pre-processing */
237     if (v && v->pre_rtn) {
238         status = (*v->pre_rtn)(q, Argv, cl, 0);
239         if (status != MR_SUCCESS)
240             goto out;
241     }
242
243     switch (q->type) {
244     case RETRIEVE:
245         /* for queries that do not permit wildcarding, check if row
246            uniquely exists */
247         if (v && v->field) {
248             status = validate_row(q, Argv, v); 
249             if (status != MR_EXISTS) break;
250         }
251
252         /* build "where" clause if needed */
253         if (q->qual) {
254             build_qual(q->qual, q->argc, Argv, qual); 
255             pqual = qual;
256         } else {
257             pqual = 0;
258         }
259
260         /* build "sort" clause if needed */
261         if (v && v->valobj) {
262             psort = build_sort(v, sort);
263         } else {
264             psort = 0;
265         }
266
267         /* if there is a followup routine, then we must save the results */
268         /* of the first query for use by the followup routine */
269         /* if q->rvar = NULL, perform post_rtn only */
270         if (q->rvar) {
271             if (v && v->post_rtn) {
272                 sq = sq_create();
273                 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
274                 if (status != MR_SUCCESS) {
275                     sq_destroy(sq);
276                     break;
277                 }
278                 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
279             } else {
280                 /* normal retrieve */
281                 status = do_retrieve(q, pqual, psort, action, actarg);
282             }
283             if (status != MR_SUCCESS) break;
284         } else {
285             status = (*v->post_rtn)(q, Argv, cl, action, actarg);
286         }
287
288         break;
289
290     case UPDATE:
291         /* see if row already exists */
292         if (v->field) {
293             status = validate_row(q, Argv, v);
294             if (status != MR_EXISTS) break;
295         }
296
297         /* build "where" clause and perform update */
298         /* if q->rvar = NULL, perform post_rtn only */
299         if (q->rvar) {
300             build_qual(q->qual, q->argc, Argv, qual);
301             incremental_before(q->rtable, qual, argv_ro);
302             status = do_update(q, &Argv[q->argc], qual, action, actarg);
303             incremental_after(q->rtable, qual, argv_ro);
304             if (status != MR_SUCCESS) break;
305             flush_name(argv_ro[0], q->rtable);
306             table_name = q->rtable;
307             if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif")) {
308                 EXEC SQL UPDATE tblstats
309                   SET updates = updates + 1, modtime = 'now'
310                   WHERE table_name = :table_name;
311             }
312         }
313
314         /* execute followup routine (if any) */
315         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
316
317         break;
318
319     case APPEND:
320         /* see if row already exists */
321         if (v->field) {
322             status = validate_row(q, Argv, v);
323             if (status != MR_NO_MATCH) break;
324         }
325
326         /* build "where" clause if needed */
327         if (q->qual) {
328             build_qual(q->qual, q->argc, Argv, qual);
329             pqual = qual;
330         } else {
331             pqual = 0;
332         }
333
334         /* perform the append */
335         /* if q->rvar = NULL, perform post_rtn only */
336         if (q->rvar) {
337             incremental_clear_before();
338             status = do_append(q, &Argv[q->argc], pqual, action, actarg);
339             if (status != MR_SUCCESS) break;
340             if (v && v->object_id) {
341                 sprintf(qual, "%s.%s = %s",q->rvar, v->object_id, 
342                         Argv[q->argc+q->vcnt]);
343                 incremental_after(q->rtable, qual, argv_ro);
344             } else
345               incremental_after(q->rtable, pqual, argv_ro);
346
347             table_name = q->rtable;
348             EXEC SQL UPDATE tblstats
349               SET appends = appends + 1, modtime = 'now'
350               WHERE table_name = :table_name;
351         }
352         
353         /* execute followup routine */
354         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
355         break;
356
357     case DELETE:
358         /* see if row already exists */
359         if (v->field) {
360             status = validate_row(q, Argv, v);
361             if (status != MR_EXISTS) break;
362         }
363
364         /* build "where" clause and perform delete */
365         /* if q->rvar = NULL, perform post_rtn only */
366         if (q->rvar) {
367             build_qual(q->qual, q->argc, Argv, qual);
368             table_name = q->rtable;
369             incremental_before(q->rtable, qual, argv_ro);
370             status = do_delete(q, qual, action, actarg);
371             incremental_clear_after();
372             if (status != MR_SUCCESS) break;
373             flush_name(argv_ro[0], q->rtable);
374             EXEC SQL UPDATE tblstats
375               SET deletes = deletes + 1, modtime = 'now'
376               WHERE table_name = :table_name;
377         }
378
379         /* execute followup routine */
380         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
381         break;
382
383     }
384
385 out:
386     if (status == MR_SUCCESS && ingres_errno != 0) {
387         com_err(whoami, MR_INTERNAL, "Server didn't notice INGRES ERROR %d",
388                        ingres_errno);
389         status = mr_errcode;
390     }
391
392     if (q->type == RETRIEVE) {
393         EXEC SQL COMMIT WORK;
394     } else {
395         if (status == MR_SUCCESS) {
396         EXEC SQL COMMIT WORK;
397             if (journal) {
398                 char buf[1024], *bp;
399                 int i;
400                 extern time_t now;
401
402                 fprintf(journal, "%% %s %s %s",
403                         cl->clname, cl->entity, ctime(&now));
404                 fprintf(journal, "%s[%d] ", q->name, cl->args->mr_version_no);
405                 for (i = 0; i < argc; i++) {
406                     if (i != 0) {
407                         putc(' ', journal);
408                     }
409                     requote(buf, argv_ro[i], sizeof(buf));
410                     fputs(buf, journal);
411                 }
412                 putc('\n', journal);
413                 fflush(journal);
414             }
415             incremental_update();
416         } else {
417             cache_abort();
418             if (ingres_errno != INGRES_DEADLOCK) {
419                 EXEC SQL ROLLBACK WORK;
420             }
421             incremental_flush();
422         }
423     }
424     cache_commit(); /* commit following abort is safe */
425
426     if (status != MR_SUCCESS && log_flags & LOG_RES)
427         com_err(whoami, status, " (Query failed)");
428     return(status);
429 }
430
431 build_qual(fmt, argc, argv, qual)
432         char *fmt;
433         int argc;
434         char *argv[];
435         char *qual;
436 {
437     register char *c;
438     register int i;
439     char *args[4];
440     char *index();
441
442     c = fmt;
443     for (i = 0; i < argc; i++) {
444         c = index(c, '%');
445         if (c++ == (char *)0) return(MR_ARGS);
446         if (*c == 's')
447             args[i] = argv[i];
448         else if (*c == 'd')
449             *(int *)&args[i] = *(int *)argv[i]; /* sigh */
450         else
451             return(MR_INGRES_ERR);
452     }
453     if (c = index(c, '%')) {
454         args[i] = args[i - 1];
455     }
456
457     switch (argc) {
458     case 0:
459         strcpy(qual, fmt);
460         break;
461
462     case 1:
463         sprintf(qual, fmt, args[0]);
464         break;
465
466     case 2:
467         sprintf(qual, fmt, args[0], args[1]);
468         break;
469
470     case 3:
471         sprintf(qual, fmt, args[0], args[1], args[2]);
472         break;
473
474     case 4:
475         sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
476         break;
477
478     default:
479         com_err(whoami, MR_INTERNAL,
480                 "Internal arg count error processing query");
481         return(MR_INTERNAL);
482     }
483     return(MR_SUCCESS);
484 }
485
486 char *
487 build_sort(v, sort)
488     register struct validate *v;
489     char *sort;
490 {
491     register struct valobj *vo;
492     register int n;
493     char elem[16];
494
495     n = v->objcnt;
496     vo = v->valobj;
497     *sort = 0;
498
499     while (--n >= 0) {
500         if (vo->type == V_SORT) {
501             sprintf(elem, "%d", vo->index + 1);    /* Result column number */
502             if (*sort) strcat(sort, ", ");
503             strcat(sort, elem);
504         }
505         vo++;
506     }
507
508     return ((*sort) ? sort : 0);
509 }
510
511
512 /* Build arguement vector, verify query and arguments */
513
514 int privileged;
515
516 mr_verify_query(cl, q, argc, argv_ro)
517     client *cl;
518     struct query *q;
519     int argc;
520     char *argv_ro[];
521 {
522     register int argreq;
523     register int status;
524     register struct validate *v = q->validate;
525     register int i;
526     register char *to,*fr,*stop;
527
528     privileged = 0;
529
530     /* copy the arguments into a local argv that we can modify */
531     if (argc >= QMAXARGS)
532       return(MR_ARGS);
533     for (i = 0; i < argc; i++) {
534         /* Single quotes must be doubled for SQL */
535         for (to=Argv[i], fr=argv_ro[i], stop=to+ARGLEN; (*fr) && (to<stop);) {
536             if(*fr=='\'') 
537               *to++ = *fr;
538             *to++ = *fr++;
539         }
540         if (*fr) 
541           return(MR_ARG_TOO_LONG);
542         *to='\0';
543
544         if (*--to == '\\')
545           return(MR_BAD_CHAR);
546     }
547
548     /* check initial query access */
549     status = check_query_access(q, Argv, cl);
550     if (status != MR_SUCCESS && status != MR_PERM)
551         return(status);
552     if (status == MR_SUCCESS)
553         privileged++;
554
555     /* check argument count */
556     argreq = q->argc;
557     if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
558     if (argc != argreq) return(MR_ARGS);
559
560     /* validate arguments */
561     if (v && v->valobj) {
562         status = validate_fields(q, Argv, v->valobj, v->objcnt);
563         if (status != MR_SUCCESS) return(status);
564     }
565
566     /* perform special query access check */
567     if (!privileged && v && v->acs_rtn) {
568         status = (*v->acs_rtn)(q, Argv, cl);
569         if (status != MR_SUCCESS && status != MR_PERM)
570             return(status);
571         if (status == MR_SUCCESS)
572             return(MR_SUCCESS);
573     }
574
575     return(privileged ? MR_SUCCESS : MR_PERM);
576 }
577
578
579 /* This routine caches info from the database.  Each query acl is stored
580  * in the query structure, and whether that acl contains everybody.
581  */
582
583 check_query_access(q, argv, cl)
584     struct query *q;
585     char *argv[];
586     client *cl;
587 {
588     EXEC SQL BEGIN DECLARE SECTION; 
589     char *name;
590     int acl_id;
591     int rowcount;
592     int errorno;
593     static int def_uid;
594     EXEC SQL END DECLARE SECTION; 
595     int status;
596     int client_id;
597     char *client_type;
598
599     /* initialize default uid */
600     if (def_uid == 0) {
601         EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login='default';
602     }
603
604     /* get query access control list */
605     if (q->acl != 0)
606       acl_id = q->acl;
607     else {
608         name = q->shortname;
609         EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
610         if (sqlca.sqlcode < 0) return(MR_INGRES_ERR);
611         if (sqlca.sqlcode == 100) return(MR_PERM);
612         q->acl = acl_id;
613
614         /* check for default access */
615         EXEC SQL SELECT member_id INTO :acl_id FROM imembers
616           WHERE list_id = :acl_id AND member_type = 'USER' 
617             AND member_id = :def_uid;
618         if (sqlca.sqlerrd[2] == 0)
619           q->everybody = 0;
620         else
621           q->everybody = 1;
622     }
623
624     if (q->everybody)
625       return(MR_SUCCESS);
626
627     if (get_client(cl, &client_type, &client_id) != MR_SUCCESS)
628       return(MR_PERM);
629     if (find_member("LIST", acl_id, client_type, client_id, 0))
630       return(MR_SUCCESS);
631     else
632       return(MR_PERM);
633 }
634
635
636 get_client(cl, client_type, client_id)
637     client *cl;
638     char **client_type;
639     int *client_id;
640 {
641     if (cl->users_id > 0) {
642         *client_id = cl->users_id;
643         *client_type = "USER";
644         return(MR_SUCCESS);
645     }
646
647     if (cl->client_id < 0) {
648         *client_id = -cl->users_id;
649         *client_type = "KERBEROS";
650         return(MR_SUCCESS);
651     }
652
653     return(MR_PERM);
654 }
655
656 find_member(list_type, list_id, member_type, member_id)
657     char *list_type;
658     EXEC SQL BEGIN DECLARE SECTION; 
659     int list_id;
660     char *member_type;
661     int member_id;
662     EXEC SQL END DECLARE SECTION;
663 {
664     EXEC SQL BEGIN DECLARE SECTION; 
665     int flag, errorno;
666     EXEC SQL END DECLARE SECTION; 
667
668     if (!strcmp(strtrim(list_type), strtrim(member_type)) &&
669         list_id == member_id)
670         return(1);
671
672     /* see if client is a direct member of list */
673     flag = 0;
674     EXEC SQL SELECT member_id INTO :flag FROM imembers
675       WHERE list_id = :list_id AND member_type = :member_type 
676         AND member_id = :member_id;
677     if(flag!=0) flag=1;             /** Not strictly necessary */
678     if (sqlca.sqlcode == 0)
679       return(flag);            
680     return(0);
681 }
682
683
684 do_retrieve(q, pqual, psort, action, actarg)            
685     register struct query *q;
686 EXEC SQL BEGIN DECLARE SECTION; 
687     char *pqual;
688     char *psort;
689 EXEC SQL END DECLARE SECTION; 
690     int (*action)();
691     char *actarg;
692 {
693     static char **vaddrs = (char **)NULL;
694     int j, rowcount;
695
696     if (!vaddrs) {
697         register int i;
698
699         if ((vaddrs = (char **)malloc(sizeof(char *) * QMAXARGS)) == NULL) {
700             com_err(whoami, MR_NO_MEM, "setting up static argv");
701             exit(1);
702         }
703         for (i = 0; i < QMAXARGS; i++) {  
704             vaddrs[i]=SQLDA->sqlvar[i].sqldata;
705         }
706     }
707
708     build_sql_stmt(stmt_buf,"SELECT",q->tlist,vaddrs,pqual);
709     if(psort) { strcat(stmt_buf," ORDER BY "); strcat(stmt_buf,psort); }
710     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf; 
711     if(sqlca.sqlcode)
712       return(MR_INTERNAL);
713     EXEC SQL DECLARE csr001 CURSOR FOR stmt;
714     EXEC SQL OPEN csr001;
715     rowcount = 0;
716     while(1) {
717         EXEC SQL FETCH csr001 USING DESCRIPTOR :SQLDA;
718         if(sqlca.sqlcode != 0) break;
719         (*action)(q->vcnt, vaddrs, actarg);
720         rowcount++;
721     }
722     EXEC SQL CLOSE csr001;
723
724     if (mr_errcode) return(mr_errcode);
725     return ((rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS);
726 }
727
728 char *sqlstrstr(str,pat)
729     char *str;
730     char *pat;
731 {
732     register char *p=pat;
733     
734     do {
735         if(*str=='\'') {    /* Skip over single-quote delimited substrings */ 
736             while(*++str && (*str!='\'')) 
737                 ; 
738             continue;
739         }
740         if(*str==*p) {
741             register char *s;
742             s=str; 
743             while(*++p && (*++s==*p))
744                 ; 
745             if(*p) p=pat;  /* failed */
746         }
747     } while(*p && *++str);
748
749     if(!*str) str=NULL;
750     return(str);
751 }
752
753 void optimize_sql_stmt(buf)
754 char *buf;
755 {
756     char *point=buf, *pat, *eopat, *esc1, *esc2, *csr;
757
758     for(point=buf; point=sqlstrstr(point,"LIKE"); point++)  {
759         /* Now pointing to string "LIKE" */
760
761         /* Look at next word */
762         for(pat=point+4; *pat==' '; pat++) ;
763
764         /* Is it a single-quote delimited string? */
765         if(*pat!='\'') continue;
766
767         /* look for "escape" clause - save escape character */
768         /* 1. Find end of pattern */
769         for(eopat=pat+1; 1; eopat++) {
770             if(*eopat=='\'') {
771                 if(eopat[1]=='\'')  /* single-quote is self-escaping */
772                     eopat++;
773                 else
774                     break;
775             }
776         }
777
778         /* 2. Look at next word */
779         for(esc1=eopat; *++esc1==' ';) ;
780
781         /* 3. esc1=0 if not "ESCAPE '?'", where the ? may be any character. */
782         if(strncmp(esc1,"ESCAPE",6)) esc1=NULL;
783
784         if(esc1) {
785             for(esc2=esc1+6; *esc2==' '; esc2++) ;
786             
787             if(*esc2++!='\'') continue; /* Bad SQL syntax. Skip. */
788             /* esc2 now points at the escape character itself */
789             if(esc2[1]!='\'') continue; /* Weird escape string. Skip. */
790         } else {
791             esc2="\\";
792         }
793
794         /* Is pattern free from special characters? */
795         for(csr=pat; csr<eopat; csr++) 
796             if((*csr=='%') || (*csr=='_') || (*csr==*esc2)) break;
797         if(csr!=eopat) continue; /* Uses pattern matching. Skip. */
798
799         /* Optimize the query statement */
800         /* 1. Change "LIKE" to " =  " */
801         memcpy(point," =  ",4);
802         
803         /* 2. Change "ESCAPE" to "      " */
804         if(esc1) {
805             memset(esc1,' ',6);
806             /* 3. Change  "'*'" to "   " */
807             /*    (Changes '''' to "    ") */
808             if(esc2) memset(esc2-1,' ',(*esc2=='\'')?4:3); 
809         }
810     }
811 }
812
813 build_sql_stmt(result_buf,cmd,targetlist,argv,qual)
814     char *result_buf;
815     char *cmd;
816     char *targetlist;
817     char *argv[];
818     char *qual;
819 {
820     char fmt_buf[MR_STMTBUF_LEN];
821     register char *res, *fmt;
822
823     if(qual)
824       sprintf(fmt_buf,"%s %s WHERE %s",cmd,targetlist,qual);
825     else
826       sprintf(fmt_buf,"%s %s",cmd,targetlist);
827
828     for(res=result_buf, fmt=fmt_buf; *fmt; fmt++) {
829         if(*fmt=='%') {
830             if(*++fmt) {
831                 switch(*fmt) {                       
832                   case '%':                              /* %% -> % */
833                     *res++ = *fmt;           
834                     break;
835                   case 's':
836                     if(*argv[0]) {
837                         *res='\0';
838                         strcat(res,*argv);
839                         while(*++res) ;
840                     }
841                     argv++;
842                     break;
843                   case 'd':
844                     sprintf(res,"%d",*(int *)*argv++);   /* print to result buffer */
845                     while(*++res) ;
846                     break;
847                   default:                               /* Swallow other %? pairs */
848                     break;
849                 }
850             } else break;
851         } else *res++ = *fmt;                            /* text -> result buffer */
852     }
853     *res='\0';
854
855     optimize_sql_stmt(result_buf);
856 }
857
858 do_update(q, argv, qual, action, actarg)
859     register struct query *q;
860     char *argv[];
861     char *qual;
862     int (*action)();
863     char *actarg;
864 {
865     build_sql_stmt(stmt_buf,"UPDATE",q->tlist,argv,qual);
866     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
867     if (mr_errcode) return(mr_errcode);
868     return(MR_SUCCESS);
869 }
870
871 do_append(q, argv, pqual, action, actarg)
872     register struct query *q;
873     char *argv[];
874     char *pqual;
875     int (*action)();
876     char *actarg;
877 {
878     build_sql_stmt(stmt_buf,"INSERT",q->tlist,argv,pqual);
879     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
880     if (mr_errcode) return(mr_errcode);
881     return(MR_SUCCESS);
882 }
883
884 do_delete(q, qual, action, actarg)
885     register struct query *q;
886     char *qual;
887     int (*action)();
888     char *actarg;
889 {
890     sprintf(stmt_buf,"DELETE FROM %s WHERE %s",q->rtable,qual);
891     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
892     if (mr_errcode) return(mr_errcode);
893     return(MR_SUCCESS);
894 }
895
896
897 /**
898  ** set_next_object_id - set next object id in values table
899  **
900  ** Inputs: object - object name in values table and in objects
901  **         table - name of table objects are found in
902  **         limit - should the ID be range limited
903  **
904  ** - called before an APPEND operation to set the next object id to
905  **   be used for the new record to the next free value
906  **
907  **/
908
909 set_next_object_id(object, table_name, limit)
910     EXEC SQL BEGIN DECLARE SECTION; 
911     char *object;
912     char *table_name;
913     int limit;
914     EXEC SQL END DECLARE SECTION; 
915 {
916     EXEC SQL BEGIN DECLARE SECTION; 
917     int value;
918     EXEC SQL END DECLARE SECTION;
919     int starting_value;
920     
921     EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :object;
922     if (sqlca.sqlerrd[2] != 1)
923         return(MR_NO_ID);
924
925     starting_value=value;
926     while (1) { 
927         if (limit && value > MAX_ID_VALUE) 
928             value = MIN_ID_VALUE;
929
930         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s=%d",object,table_name,object,value);  
931         EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf; 
932         if(sqlca.sqlcode)
933           return(MR_INTERNAL);
934         EXEC SQL DECLARE csr002 CURSOR FOR stmt;
935         EXEC SQL OPEN csr002;
936         EXEC SQL FETCH csr002 USING DESCRIPTOR :SQLDA;
937         if (sqlca.sqlcode < 0) return(mr_errcode);
938         if (sqlca.sqlcode == 100) break;
939
940         EXEC SQL CLOSE csr002;
941         value++;
942         if (limit && value == starting_value) {   
943             com_err(whoami,0,"All id values have been used");
944             return(MR_NO_ID);
945         }
946     }
947     EXEC SQL CLOSE csr002;
948
949     if (LOG_RES)
950         com_err(whoami, 0, "setting ID %s to %d", object, value);
951     EXEC SQL UPDATE numvalues SET value = :value WHERE name = :object;
952     return(MR_SUCCESS);
953 }
954
955
956 /* Turn a kerberos name into the user's ID of the account that principal
957  * owns.  Sets the kerberos ID and user ID.
958  */
959
960 int set_krb_mapping(name, login, ok, kid, uid)
961 char *name;
962 char *login;
963 int ok;
964 int *kid;
965 int *uid;
966 {
967     EXEC SQL BEGIN DECLARE SECTION; 
968     int u_id, k_id;
969     char *krbname;
970     EXEC SQL END DECLARE SECTION; 
971
972     krbname = name;
973     *kid = 0;
974     *uid = 0;
975
976     EXEC SQL SELECT km.users_id, km.string_id INTO :u_id, :k_id
977       FROM krbmap km, strings str
978       WHERE km.string_id = str.string_id AND str.string = :krbname;
979     EXEC SQL COMMIT WORK;
980
981     if (ingres_errno) return(mr_errcode);
982     
983     if (sqlca.sqlerrd[2] == 1) {    /* rowcount */
984         *kid = -k_id;
985         *uid = u_id;
986         return(MR_SUCCESS);
987     }
988
989     if (name_to_id(name, "STRINGS", &k_id) == MR_SUCCESS)
990       *kid = -k_id;
991
992     if (!ok) {             
993         *uid = *kid;
994         return(MR_SUCCESS);
995     }
996
997     if (name_to_id(login, "USERS", uid) != MR_SUCCESS)
998       *uid = 0;
999
1000     if (*kid == 0)
1001       *kid = *uid;
1002     if (ingres_errno) return(mr_errcode);
1003     return(MR_SUCCESS);
1004 }
1005
1006
1007 /* For now this just checks the argc's.  It should also see that there
1008  * are no duplicate names.
1009  */
1010
1011 sanity_check_queries()
1012 {
1013     register int i;
1014     int maxv = 0, maxa = 0;
1015 #ifdef MULTIPROTOCOLS
1016     extern int QueryCount1, QueryCount2;
1017     extern struct query Queries1[], Queries2[];
1018 #else
1019     extern int QueryCount2;
1020     extern struct query Queries2[];
1021 #endif MULTIPROTOCOLS
1022
1023 #define MAX(x,y) ((x) > (y) ? (x) : (y))
1024
1025 #ifdef MULTIPROTOCOLS
1026     for (i = 0; i < QueryCount1; i++) {
1027         maxv = MAX(maxv, Queries1[i].vcnt);
1028         maxa = MAX(maxa, Queries1[i].argc);
1029     }
1030 #endif MULTIPROTOCOLS
1031     for (i = 0; i < QueryCount2; i++) {
1032         maxv = MAX(maxv, Queries2[i].vcnt);
1033         maxa = MAX(maxa, Queries2[i].argc);
1034     }
1035     if (MAX(maxv, maxa) > QMAXARGS) {
1036         com_err(whoami, 0, "A query has more args than QMAXARGS");
1037         exit(1);
1038     }
1039 }
1040
1041 /* eof:qrtn.dc */
This page took 0.126192 seconds and 5 git commands to generate.