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